From 750bceebf2e9724d1b2def37aa1559c60ca9d707 Mon Sep 17 00:00:00 2001 From: Chris Feger Date: Thu, 7 May 2020 20:20:48 -0400 Subject: [PATCH] Add FSPXI interfaces (#446) --- libctru/include/3ds.h | 1 + libctru/include/3ds/services/fs.h | 29 +- libctru/include/3ds/services/fspxi.h | 613 ++++++++++++ libctru/source/services/fs.c | 22 +- libctru/source/services/fspxi.c | 1386 ++++++++++++++++++++++++++ 5 files changed, 2026 insertions(+), 25 deletions(-) create mode 100644 libctru/include/3ds/services/fspxi.h create mode 100644 libctru/source/services/fspxi.c diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 2f8c22a..48e1bc8 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -40,6 +40,7 @@ extern "C" { #include <3ds/services/csnd.h> #include <3ds/services/dsp.h> #include <3ds/services/fs.h> +#include <3ds/services/fspxi.h> #include <3ds/services/fsreg.h> #include <3ds/services/frd.h> #include <3ds/services/gspgpu.h> diff --git a/libctru/include/3ds/services/fs.h b/libctru/include/3ds/services/fs.h index 8db6c15..1d94630 100644 --- a/libctru/include/3ds/services/fs.h +++ b/libctru/include/3ds/services/fs.h @@ -135,6 +135,7 @@ typedef enum { ARCHIVE_ACTION_COMMIT_SAVE_DATA = 0, ///< Commits save data changes. No inputs/outputs. ARCHIVE_ACTION_GET_TIMESTAMP = 1, ///< Retrieves a file's last-modified timestamp. In: "u16*, UTF-16 Path", Out: "u64, Time Stamp". + ARCHIVE_ACTION_UNKNOWN = 0x789D, //< Unknown action; calls FSPXI command 0x56. In: "FS_Path instance", Out: "u32[4], Unknown" } FS_ArchiveAction; /// Secure save control actions. @@ -444,7 +445,7 @@ Result FSUSER_IsSdmcDetected(bool *detected); /** * @brief Gets whether the SD card is writable. - * @param detected Pointer to output the writable status to. + * @param writable Pointer to output the writable status to. */ Result FSUSER_IsSdmcWritable(bool *writable); @@ -537,7 +538,7 @@ Result FSUSER_CardNorDirectCommandWithAddress(u8 commandId, u32 address); * @param size Size of the output buffer. * @param output Output buffer. */ -Result FSUSER_CardNorDirectRead(u8 commandId, u32 size, u8* output); +Result FSUSER_CardNorDirectRead(u8 commandId, u32 size, void* output); /** * @brief Executes a CARDNOR direct read with an address. @@ -546,7 +547,7 @@ Result FSUSER_CardNorDirectRead(u8 commandId, u32 size, u8* output); * @param size Size of the output buffer. * @param output Output buffer. */ -Result FSUSER_CardNorDirectReadWithAddress(u8 commandId, u32 address, u32 size, u8* output); +Result FSUSER_CardNorDirectReadWithAddress(u8 commandId, u32 address, u32 size, void* output); /** * @brief Executes a CARDNOR direct write. @@ -554,7 +555,7 @@ Result FSUSER_CardNorDirectReadWithAddress(u8 commandId, u32 address, u32 size, * @param size Size of the input buffer. * @param output Input buffer. */ -Result FSUSER_CardNorDirectWrite(u8 commandId, u32 size, u8* input); +Result FSUSER_CardNorDirectWrite(u8 commandId, u32 size, const void* input); /** * @brief Executes a CARDNOR direct write with an address. @@ -563,7 +564,7 @@ Result FSUSER_CardNorDirectWrite(u8 commandId, u32 size, u8* input); * @param size Size of the input buffer. * @param input Input buffer. */ -Result FSUSER_CardNorDirectWriteWithAddress(u8 commandId, u32 address, u32 size, u8* input); +Result FSUSER_CardNorDirectWriteWithAddress(u8 commandId, u32 address, u32 size, const void* input); /** * @brief Executes a CARDNOR 4xIO direct read. @@ -572,7 +573,7 @@ Result FSUSER_CardNorDirectWriteWithAddress(u8 commandId, u32 address, u32 size, * @param size Size of the output buffer. * @param output Output buffer. */ -Result FSUSER_CardNorDirectRead_4xIO(u8 commandId, u32 address, u32 size, u8* output); +Result FSUSER_CardNorDirectRead_4xIO(u8 commandId, u32 address, u32 size, void* output); /** * @brief Executes a CARDNOR direct CPU write without verify. @@ -580,7 +581,7 @@ Result FSUSER_CardNorDirectRead_4xIO(u8 commandId, u32 address, u32 size, u8* ou * @param size Size of the input buffer. * @param output Input buffer. */ -Result FSUSER_CardNorDirectCpuWriteWithoutVerify(u32 address, u32 size, u8* input); +Result FSUSER_CardNorDirectCpuWriteWithoutVerify(u32 address, u32 size, const void* input); /** * @brief Executes a CARDNOR direct sector erase without verify. @@ -610,7 +611,7 @@ Result FSUSER_SetCardSpiBaudRate(FS_CardSpiBaudRate baudRate); /** * @brief Sets the CARDSPI bus mode. - * @param baudRate Bus mode to set. + * @param busMode Bus mode to set. */ Result FSUSER_SetCardSpiBusMode(FS_CardSpiBusMode busMode); @@ -632,7 +633,7 @@ Result FSUSER_GetSpecialContentIndex(u16* index, FS_MediaType mediaType, u64 pro * @param programId ID of the program. * @param header Pointer to output the legacy ROM header to. (size = 0x3B4) */ -Result FSUSER_GetLegacyRomHeader(FS_MediaType mediaType, u64 programId, u8* header); +Result FSUSER_GetLegacyRomHeader(FS_MediaType mediaType, u64 programId, void* header); /** * @brief Gets the legacy banner data of a program. @@ -640,7 +641,7 @@ Result FSUSER_GetLegacyRomHeader(FS_MediaType mediaType, u64 programId, u8* head * @param programId ID of the program. * @param header Pointer to output the legacy banner data to. (size = 0x23C0) */ -Result FSUSER_GetLegacyBannerData(FS_MediaType mediaType, u64 programId, u8* banner); +Result FSUSER_GetLegacyBannerData(FS_MediaType mediaType, u64 programId, void* banner); /** * @brief Checks a process's authority to access a save data archive. @@ -697,7 +698,7 @@ Result FSUSER_GetFormatInfo(u32* totalSize, u32* directories, u32* files, bool* * @param programId ID of the program. * @param header Pointer to output the legacy ROM header to. */ -Result FSUSER_GetLegacyRomHeader2(u32 headerSize, FS_MediaType mediaType, u64 programId, u8* header); +Result FSUSER_GetLegacyRomHeader2(u32 headerSize, FS_MediaType mediaType, u64 programId, void* header); /** * @brief Gets the CTR SDMC root path. @@ -745,7 +746,7 @@ Result FSUSER_FormatSaveData(FS_ArchiveID archiveId, FS_Path path, u32 blocks, u * @param programId ID of the program. * @param header Pointer to output the legacy sub banner data to. */ -Result FSUSER_GetLegacySubBannerData(u32 bannerSize, FS_MediaType mediaType, u64 programId, u8* banner); +Result FSUSER_GetLegacySubBannerData(u32 bannerSize, FS_MediaType mediaType, u64 programId, void* banner); /** * @brief Hashes the given data and outputs a SHA256 hash. @@ -762,7 +763,7 @@ Result FSUSER_UpdateSha256Context(const void* data, u32 inputSize, u8* hash); * @param size Size of the buffer. * @param data Buffer to read to. */ -Result FSUSER_ReadSpecialFile(u32* bytesRead, u64 fileOffset, u32 size, u8* data); +Result FSUSER_ReadSpecialFile(u32* bytesRead, u64 fileOffset, u32 size, void* data); /** * @brief Gets the size of a special file. @@ -871,7 +872,7 @@ Result FSUSER_SetCtrCardLatencyParameter(u64 latency, bool emulateEndurance); /** * @brief Toggles cleaning up invalid save data. - * @param Whether to enable cleaning up invalid save data. + * @param enable Whether to enable cleaning up invalid save data. */ Result FSUSER_SwitchCleanupInvalidSaveData(bool enable); diff --git a/libctru/include/3ds/services/fspxi.h b/libctru/include/3ds/services/fspxi.h new file mode 100644 index 0000000..53528a7 --- /dev/null +++ b/libctru/include/3ds/services/fspxi.h @@ -0,0 +1,613 @@ +/** + * @file fspxi.h + * @brief Service interface for PxiFS services. This is normally not accessible to userland apps. https://3dbrew.org/wiki/Filesystem_services_PXI + */ +#pragma once + +#include <3ds/services/fs.h> +#include <3ds/types.h> + +typedef u64 FSPXI_Archive; +typedef u64 FSPXI_File; +typedef u64 FSPXI_Directory; + +/** + * @brief Opens a file. + * @param out Pointer to output the file handle to. + * @param archive Archive containing the file. + * @param path Path of the file. + * @param flags Flags to open the file with. + * @param attributes Attributes of the file. + */ +Result FSPXI_OpenFile(Handle serviceHandle, FSPXI_File* out, FSPXI_Archive archive, FS_Path path, u32 flags, u32 attributes); + +/** + * @brief Deletes a file. + * @param archive Archive containing the file. + * @param path Path of the file. + */ +Result FSPXI_DeleteFile(Handle serviceHandle, FSPXI_Archive archive, FS_Path path); + +/** + * @brief Renames a file. + * @param srcArchive Archive containing the source file. + * @param srcPath Path of the source file. + * @param dstArchive Archive containing the destination file. + * @param dstPath Path of the destination file. + */ +Result FSPXI_RenameFile(Handle serviceHandle, FSPXI_Archive srcArchive, FS_Path srcPath, FSPXI_Archive dstArchive, FS_Path dstPath); + +/** + * @brief Deletes a directory. + * @param archive Archive containing the directory. + * @param path Path of the directory. + */ +Result FSPXI_DeleteDirectory(Handle serviceHandle, FSPXI_Archive archive, FS_Path path); + +/** + * @brief Creates a file. + * @param archive Archive to create the file in. + * @param path Path of the file. + * @param attributes Attributes of the file. + * @param size Size of the file. + */ +Result FSPXI_CreateFile(Handle serviceHandle, FSPXI_Archive archive, FS_Path path, u32 attributes, u64 fileSize); + +/** + * @brief Creates a directory. + * @param archive Archive to create the directory in. + * @param path Path of the directory. + * @param attributes Attributes of the directory. + */ +Result FSPXI_CreateDirectory(Handle serviceHandle, FSPXI_Archive archive, FS_Path path, u32 attributes); + +/** + * @brief Renames a directory. + * @param srcArchive Archive containing the source directory. + * @param srcPath Path of the source directory. + * @param dstArchive Archive containing the destination directory. + * @param dstPath Path of the destination directory. + */ +Result FSPXI_RenameDirectory(Handle serviceHandle, FSPXI_Archive srcArchive, FS_Path srcPath, FSPXI_Archive dstArchive, FS_Path dstPath); + +/** + * @brief Opens a directory. + * @param out Pointer to output the directory handle to. + * @param archive Archive containing the directory. + * @param path Path of the directory. + */ +Result FSPXI_OpenDirectory(Handle serviceHandle, FSPXI_Directory* out, FSPXI_Archive archive, FS_Path path); + +/** + * @brief Reads from a file. + * @param file File to read from. + * @param bytesRead Pointer to output the number of read bytes to. + * @param offset Offset to read from. + * @param buffer Buffer to read to. + * @param size Size of the buffer. + */ +Result FSPXI_ReadFile(Handle serviceHandle, FSPXI_File file, u32* bytesRead, u64 offset, void* buffer, u32 size); + +/** + * @brief Calculate SHA256 of a file. + * @param file File to calculate the hash of. + * @param buffer Buffer to output the hash to. + * @param size Size of the buffer. + */ +Result FSPXI_CalculateFileHashSHA256(Handle serviceHandle, FSPXI_File file, void* buffer, u32 size); + +/** + * @brief Writes to a file. + * @param file File to write to. + * @param bytesWritten Pointer to output the number of bytes written to. + * @param offset Offset to write to. + * @param buffer Buffer to write from. + * @param size Size of the buffer. + * @param flags Flags to use when writing. + */ +Result FSPXI_WriteFile(Handle serviceHandle, FSPXI_File file, u32* bytesWritten, u64 offset, const void* buffer, u32 size, u32 flags); + +/** + * @brief Calculates the MAC used in a DISA/DIFF header? + * @param file Unsure + * @param inBuffer 0x100-byte DISA/DIFF input buffer. + * @param inSize Size of inBuffer. + * @param outBuffer Buffer to write MAC to. + * @param outSize Size of outBuffer. + */ +Result FSPXI_CalcSavegameMAC(Handle serviceHandle, FSPXI_File file, const void* inBuffer, u32 inSize, void* outBuffer, u32 outSize); + +/** + * @brief Get size of a file + * @param file File to get the size of. + * @param size Pointer to output size to. + */ +Result FSPXI_GetFileSize(Handle serviceHandle, FSPXI_File file, u64* size); + +/** + * @brief Set size of a file + * @param file File to set the size of + * @param size Size to set the file to + */ +Result FSPXI_SetFileSize(Handle serviceHandle, FSPXI_File file, u64 size); + +/** + * @brief Close a file + * @param file File to close + */ +Result FSPXI_CloseFile(Handle serviceHandle, FSPXI_File file); + +/** + * @brief Reads one or more directory entries. + * @param directory Directory to read from. + * @param entriesRead Pointer to output the number of entries read to. + * @param entryCount Number of entries to read. + * @param entryOut Pointer to output directory entries to. + */ +Result FSPXI_ReadDirectory(Handle serviceHandle, FSPXI_Directory directory, u32* entriesRead, u32 entryCount, FS_DirectoryEntry* entries); + +/** + * @brief Close a directory + * @param directory Directory to close. + */ +Result FSPXI_CloseDirectory(Handle serviceHandle, FSPXI_Directory directory); + +/** + * @brief Opens an archive. + * @param archive Pointer to output the opened archive to. + * @param id ID of the archive. + * @param path Path of the archive. + */ +Result FSPXI_OpenArchive(Handle serviceHandle, FSPXI_Archive* archive, FS_ArchiveID archiveID, FS_Path path); + +/** + * @brief Checks if the archive contains a file at path. + * @param archive Archive to check. + * @param out Pointer to output existence to. + * @param path Path to check for file + */ +Result FSPXI_HasFile(Handle serviceHandle, FSPXI_Archive archive, bool* out, FS_Path path); + +/** + * @brief Checks if the archive contains a directory at path. + * @param archive Archive to check. + * @param out Pointer to output existence to. + * @param path Path to check for directory + */ +Result FSPXI_HasDirectory(Handle serviceHandle, FSPXI_Archive archive, bool* out, FS_Path path); + +/** + * @brief Commits an archive's save data. + * @param archive Archive to commit. + * @param id Archive action sent by FSUSER_ControlArchive. Must not be 0 or 0x789D + * @remark Unsure why id is sent. This appears to be the default action for FSUSER_ControlArchive, with every action other than 0 and 0x789D being sent to this command. + */ +Result FSPXI_CommitSaveData(Handle serviceHandle, FSPXI_Archive archive, u32 id); + +/** + * @brief Close an archive + * @param archive Archive to close. + */ +Result FSPXI_CloseArchive(Handle serviceHandle, FSPXI_Archive archive); + +/** + * @brief Unknown 0x17. Appears to be an "is archive handle valid" command? + * @param archive Archive handle to check validity of. + * @param out Pointer to output validity to. + */ +Result FSPXI_Unknown0x17(Handle serviceHandle, FSPXI_Archive archive, bool* out); + +/** + * @brief Gets the inserted card type. + * @param out Pointer to output the card type to. + */ +Result FSPXI_GetCardType(Handle serviceHandle, FS_CardType* out); + +/** + * @brief Gets the SDMC archive resource information. + * @param out Pointer to output the archive resource information to. + */ +Result FSPXI_GetSdmcArchiveResource(Handle serviceHandle, FS_ArchiveResource* out); + +/** + * @brief Gets the NAND archive resource information. + * @param out Pointer to output the archive resource information to. + */ +Result FSPXI_GetNandArchiveResource(Handle serviceHandle, FS_ArchiveResource* out); + +/** + * @brief Gets the error code from the SDMC FatFS driver + * @param out Pointer to output the error code to + */ +Result FSPXI_GetSdmcFatFsError(Handle serviceHandle, u32* out); + +/** + * @brief Gets whether PXIFS0 detects the SD + * @param out Pointer to output the detection status to + */ +Result FSPXI_IsSdmcDetected(Handle serviceHandle, bool* out); + +/** + * @brief Gets whether PXIFS0 can write to the SD + * @param out Pointer to output the writable status to + */ +Result FSPXI_IsSdmcWritable(Handle serviceHandle, bool* out); + +/** + * @brief Gets the SDMC CID + * @param out Buffer to output the CID to. + * @param size Size of buffer. + */ +Result FSPXI_GetSdmcCid(Handle serviceHandle, void* out, u32 size); + +/** + * @brief Gets the NAND CID + * @param out Buffer to output the CID to. + * @param size Size of buffer. + */ +Result FSPXI_GetNandCid(Handle serviceHandle, void* out, u32 size); + +/** + * @brief Gets the SDMC speed info + * @param out Buffer to output the speed info to. + */ +Result FSPXI_GetSdmcSpeedInfo(Handle serviceHandle, u32* out); + +/** + * @brief Gets the NAND speed info + * @param out Buffer to output the speed info to. + */ +Result FSPXI_GetNandSpeedInfo(Handle serviceHandle, u32* out); + +/** + * @brief Gets the SDMC log + * @param out Buffer to output the log to. + * @param size Size of buffer. + */ +Result FSPXI_GetSdmcLog(Handle serviceHandle, void* out, u32 size); + +/** + * @brief Gets the NAND log + * @param out Buffer to output the log to. + * @param size Size of buffer. + */ +Result FSPXI_GetNandLog(Handle serviceHandle, void* out, u32 size); + +/// Clears the SDMC log +Result FSPXI_ClearSdmcLog(Handle serviceHandle); + +/// Clears the NAND log +Result FSPXI_ClearNandLog(Handle serviceHandle); + +/** + * @brief Gets whether a card is inserted. + * @param inserted Pointer to output the insertion status to. + */ +Result FSPXI_CardSlotIsInserted(Handle serviceHandle, bool* inserted); + +/** + * @brief Powers on the card slot. + * @param status Pointer to output the power status to. + */ +Result FSPXI_CardSlotPowerOn(Handle serviceHandle, bool* status); + +/** + * @brief Powers off the card slot. + * @param status Pointer to output the power status to. + */ +Result FSPXI_CardSlotPowerOff(Handle serviceHandle, bool* status); + +/** + * @brief Gets the card's power status. + * @param status Pointer to output the power status to. + */ +Result FSPXI_CardSlotGetCardIFPowerStatus(Handle serviceHandle, bool* status); + +/** + * @brief Executes a CARDNOR direct command. + * @param commandId ID of the command. + */ +Result FSPXI_CardNorDirectCommand(Handle serviceHandle, u8 commandId); + +/** + * @brief Executes a CARDNOR direct command with an address. + * @param commandId ID of the command. + * @param address Address to provide. + */ +Result FSPXI_CardNorDirectCommandWithAddress(Handle serviceHandle, u8 commandId, u32 address); + +/** + * @brief Executes a CARDNOR direct read. + * @param commandId ID of the command. + * @param size Size of the output buffer. + * @param output Output buffer. + */ +Result FSPXI_CardNorDirectRead(Handle serviceHandle, u8 commandId, u32 size, void* output); + +/** + * @brief Executes a CARDNOR direct read with an address. + * @param commandId ID of the command. + * @param address Address to provide. + * @param size Size of the output buffer. + * @param output Output buffer. + */ +Result FSPXI_CardNorDirectReadWithAddress(Handle serviceHandle, u8 commandId, u32 address, u32 size, void* output); + +/** + * @brief Executes a CARDNOR direct write. + * @param commandId ID of the command. + * @param size Size of the input buffer. + * @param output Input buffer. + * @remark Stubbed in latest firmware, since ?.?.? + */ +Result FSPXI_CardNorDirectWrite(Handle serviceHandle, u8 commandId, u32 size, const void* input); + +/** + * @brief Executes a CARDNOR direct write with an address. + * @param commandId ID of the command. + * @param address Address to provide. + * @param size Size of the input buffer. + * @param input Input buffer. + */ +Result FSPXI_CardNorDirectWriteWithAddress(Handle serviceHandle, u8 commandId, u32 address, u32 size, const void* input); + +/** + * @brief Executes a CARDNOR 4xIO direct read. + * @param commandId ID of the command. + * @param address Address to provide. + * @param size Size of the output buffer. + * @param output Output buffer. + */ +Result FSPXI_CardNorDirectRead_4xIO(Handle serviceHandle, u8 commandId, u32 address, u32 size, void* output); + +/** + * @brief Executes a CARDNOR direct CPU write without verify. + * @param address Address to provide. + * @param size Size of the input buffer. + * @param output Input buffer. + */ +Result FSPXI_CardNorDirectCpuWriteWithoutVerify(Handle serviceHandle, u32 address, u32 size, const void* input); + +/** + * @brief Executes a CARDNOR direct sector erase without verify. + * @param address Address to provide. + */ +Result FSPXI_CardNorDirectSectorEraseWithoutVerify(Handle serviceHandle, u32 address); + +/** + * @brief Gets an NCCH's product info + * @param info Pointer to output the product info to. + * @param archive Open NCCH content archive + */ +Result FSPXI_GetProductInfo(Handle serviceHandle, FS_ProductInfo* info, FSPXI_Archive archive); + +/** + * @brief Sets the CARDSPI baud rate. + * @param baudRate Baud rate to set. + */ +Result FSPXI_SetCardSpiBaudrate(Handle serviceHandle, FS_CardSpiBaudRate baudRate); + +/** + * @brief Sets the CARDSPI bus mode. + * @param busMode Bus mode to set. + */ +Result FSPXI_SetCardSpiBusMode(Handle serviceHandle, FS_CardSpiBusMode busMode); + +/** + * @brief Sends initialization info to ARM9 + * @param unk FS sends *(0x1FF81086) + */ +Result FSPXI_SendInitializeInfoTo9(Handle serviceHandle, u8 unk); + +/** + * @brief Creates ext save data. + * @param info Info of the save data. + */ +Result FSPXI_CreateExtSaveData(Handle serviceHandle, FS_ExtSaveDataInfo info); + +/** + * @brief Deletes ext save data. + * @param info Info of the save data. + */ +Result FSPXI_DeleteExtSaveData(Handle serviceHandle, FS_ExtSaveDataInfo info); + +/** + * @brief Enumerates ext save data. + * @param idsWritten Pointer to output the number of IDs written to. + * @param idsSize Size of the IDs buffer. + * @param mediaType Media type to enumerate over. + * @param idSize Size of each ID element. + * @param shared Whether to enumerate shared ext save data. + * @param ids Pointer to output IDs to. + */ +Result FSPXI_EnumerateExtSaveData(Handle serviceHandle, u32* idsWritten, u32 idsSize, FS_MediaType mediaType, u32 idSize, bool shared, u8* ids); + +/** + * @brief Gets a special content's index. + * @param index Pointer to output the index to. + * @param mediaType Media type of the special content. + * @param programId Program ID owning the special content. + * @param type Type of special content. + */ +Result FSPXI_GetSpecialContentIndex(Handle serviceHandle, u16* index, FS_MediaType mediaType, u64 programId, FS_SpecialContentType type); + +/** + * @brief Gets the legacy ROM header of a program. + * @param mediaType Media type of the program. + * @param programId ID of the program. + * @param header Pointer to output the legacy ROM header to. (size = 0x3B4) + */ +Result FSPXI_GetLegacyRomHeader(Handle serviceHandle, FS_MediaType mediaType, u64 programId, void* header); + +/** + * @brief Gets the legacy banner data of a program. + * @param mediaType Media type of the program. + * @param programId ID of the program. + * @param banner Pointer to output the legacy banner data to. (size = 0x23C0) + * @param unk Unknown. Always 1? + */ +Result FSPXI_GetLegacyBannerData(Handle serviceHandle, FS_MediaType mediaType, u64 programId, void* banner, u8 unk); + +/** + * @brief Formats the CARDNOR device. + * @param unk Unknown. Transaction? + */ +Result FSPXI_FormatCardNorDevice(Handle serviceHandle, u32 unk); + +/// Deletes the 3DS SDMC root. +Result FSPXI_DeleteSdmcRoot(Handle serviceHandle); + +/// Deletes all ext save data on the NAND. +Result FSPXI_DeleteAllExtSaveDataOnNand(Handle serviceHandle); + +/// Initializes the CTR file system. +Result FSPXI_InitializeCtrFilesystem(Handle serviceHandle); + +/// Creates the FS seed. +Result FSPXI_CreateSeed(Handle serviceHandle); + +/** + * @brief Gets the CTR SDMC root path. + * @param out Pointer to output the root path to. + * @param length Length of the output buffer in bytes. + */ +Result FSPXI_GetSdmcCtrRootPath(Handle serviceHandle, u16* out, u32 length); + +/** + * @brief Gets an archive's resource information. + * @param archiveResource Pointer to output the archive resource information to. + * @param mediaType System media type to check. + */ +Result FSPXI_GetArchiveResource(Handle serviceHandle, FS_ArchiveResource* archiveResource, FS_SystemMediaType mediaType); + +/** + * @brief Exports the integrity verification seed. + * @param seed Pointer to output the seed to. + */ +Result FSPXI_ExportIntegrityVerificationSeed(Handle serviceHandle, FS_IntegrityVerificationSeed* seed); + +/** + * @brief Imports an integrity verification seed. + * @param seed Seed to import. + */ +Result FSPXI_ImportIntegrityVerificationSeed(Handle serviceHandle, const FS_IntegrityVerificationSeed* seed); + +/** + * @brief Gets the legacy sub banner data of a program. + * @param bannerSize Size of the banner. + * @param mediaType Media type of the program. + * @param programId ID of the program. + * @param header Pointer to output the legacy sub banner data to. + */ +Result FSPXI_GetLegacySubBannerData(Handle serviceHandle, u32 bannerSize, FS_MediaType mediaType, u64 programId, void* banner); + +/** + * @brief Generates random bytes. Uses same code as PSPXI_GenerateRandomBytes + * @param buf Buffer to output random bytes to. + * @param size Size of buffer. + */ +Result FSPXI_GenerateRandomBytes(Handle serviceHandle, void* buffer, u32 size); + +/** + * @brief Gets the last modified time of a file in an archive. + * @param archive The archive that contains the file. + * @param out The pointer to write the timestamp to. + * @param path The UTF-16 path of the file. + * @param size The size of the path. + */ +Result FSPXI_GetFileLastModified(Handle serviceHandle, FSPXI_Archive archive, u64* out, const u16* path, u32 size); + +/** + * @brief Reads from a special file. + * @param bytesRead Pointer to output the number of bytes read to. + * @param fileOffset Offset of the file. + * @param size Size of the buffer. + * @param data Buffer to read to. + */ +Result FSPXI_ReadSpecialFile(Handle serviceHandle, u32* bytesRead, u64 fileOffset, u32 size, void* data); + +/** + * @brief Gets the size of a special file. + * @param fileSize Pointer to output the size to. + */ +Result FSPXI_GetSpecialFileSize(Handle serviceHandle, u64* fileSize); + +/** + * @brief Initiates a device move as the source device. + * @param context Pointer to output the context to. + */ +Result FSPXI_StartDeviceMoveAsSource(Handle serviceHandle, FS_DeviceMoveContext* context); + +/** + * @brief Initiates a device move as the destination device. + * @param context Context to use. + * @param clear Whether to clear the device's data first. + */ +Result FSPXI_StartDeviceMoveAsDestination(Handle serviceHandle, FS_DeviceMoveContext context, bool clear); + +/** + * @brief Reads data and stores SHA256 hashes of blocks + * @param file File to read from. + * @param bytesRead Pointer to output the number of read bytes to. + * @param offset Offset to read from. + * @param readBuffer Pointer to store read data in. + * @param readBufferSize Size of readBuffer. + * @param hashtable Pointer to store SHA256 hashes in. + * @param hashtableSize Size of hashtable. + * @param unk Unknown. Always 0x00001000? Possibly block size? + */ +Result FSPXI_ReadFileSHA256(Handle serviceHandle, FSPXI_File file, u32* bytesRead, u64 offset, void* readBuffer, u32 readBufferSize, void* hashtable, u32 hashtableSize, u32 unk); + +/** + * @brief Assumedly writes data and stores SHA256 hashes of blocks + * @param file File to write to. + * @param bytesWritten Pointer to output the number of written bytes to. + * @param offset Offset to write to. + * @param writeBuffer Buffer to write from. + * @param writeBufferSize Size of writeBuffer. + * @param hashtable Pointer to store SHA256 hashes in. + * @param hashtableSize Size of hashtable + * @param unk1 Unknown. Might match with ReadFileSHA256's unknown? + * @param unk2 Unknown. Might match with ReadFileSHA256's unknown? + */ +Result FSPXI_WriteFileSHA256(Handle serviceHandle, FSPXI_File file, u32* bytesWritten, u64 offset, const void* writeBuffer, u32 writeBufferSize, void* hashtable, u32 hashtableSize, u32 unk1, u32 unk2); + +/** + * @brief Configures CTRCARD latency emulation. + * @param latency Latency to apply. + */ +Result FSPXI_SetCtrCardLatencyParameter(Handle serviceHandle, u64 latency); + +/** + * @brief Sets the file system priority. + * @param priority Priority to set. + */ +Result FSPXI_SetPriority(Handle serviceHandle, u32 priority); + +/** + * @brief Toggles cleaning up invalid save data. + * @param enable Whether to enable cleaning up invalid save data. + */ +Result FSPXI_SwitchCleanupInvalidSaveData(Handle serviceHandle, bool enable); + +/** + * @brief Enumerates system save data. + * @param idsWritten Pointer to output the number of IDs written to. + * @param idsSize Size of the IDs buffer. + * @param ids Pointer to output IDs to. + */ +Result FSPXI_EnumerateSystemSaveData(Handle serviceHandle, u32* idsWritten, u32 idsSize, u32* ids); + +/** + * @brief Reads the NAND report. + * @param unk Unknown + * @param buffer Buffer to write the report to. + * @param size Size of buffer + */ +Result FSPXI_ReadNandReport(Handle serviceHandle, void* buffer, u32 size, u32 unk); + +/** + * @brief Unknown command 0x56 + * @remark Called by FSUSER_ControlArchive with ArchiveAction 0x789D + */ +Result FSPXI_Unknown0x56(Handle serviceHandle, u32 out[4], FS_Archive archive, FS_Path path); diff --git a/libctru/source/services/fs.c b/libctru/source/services/fs.c index d528d7b..526e9f7 100644 --- a/libctru/source/services/fs.c +++ b/libctru/source/services/fs.c @@ -731,7 +731,7 @@ Result FSUSER_CardNorDirectCommandWithAddress(u8 commandId, u32 address) return cmdbuf[1]; } -Result FSUSER_CardNorDirectRead(u8 commandId, u32 size, u8* output) +Result FSUSER_CardNorDirectRead(u8 commandId, u32 size, void* output) { u32 *cmdbuf = getThreadCommandBuffer(); @@ -747,7 +747,7 @@ Result FSUSER_CardNorDirectRead(u8 commandId, u32 size, u8* output) return cmdbuf[1]; } -Result FSUSER_CardNorDirectReadWithAddress(u8 commandId, u32 address, u32 size, u8* output) +Result FSUSER_CardNorDirectReadWithAddress(u8 commandId, u32 address, u32 size, void* output) { u32 *cmdbuf = getThreadCommandBuffer(); @@ -764,7 +764,7 @@ Result FSUSER_CardNorDirectReadWithAddress(u8 commandId, u32 address, u32 size, return cmdbuf[1]; } -Result FSUSER_CardNorDirectWrite(u8 commandId, u32 size, u8* input) +Result FSUSER_CardNorDirectWrite(u8 commandId, u32 size, const void* input) { u32 *cmdbuf = getThreadCommandBuffer(); @@ -780,7 +780,7 @@ Result FSUSER_CardNorDirectWrite(u8 commandId, u32 size, u8* input) return cmdbuf[1]; } -Result FSUSER_CardNorDirectWriteWithAddress(u8 commandId, u32 address, u32 size, u8* input) +Result FSUSER_CardNorDirectWriteWithAddress(u8 commandId, u32 address, u32 size, const void* input) { u32 *cmdbuf = getThreadCommandBuffer(); @@ -797,7 +797,7 @@ Result FSUSER_CardNorDirectWriteWithAddress(u8 commandId, u32 address, u32 size, return cmdbuf[1]; } -Result FSUSER_CardNorDirectRead_4xIO(u8 commandId, u32 address, u32 size, u8* output) +Result FSUSER_CardNorDirectRead_4xIO(u8 commandId, u32 address, u32 size, void* output) { u32 *cmdbuf = getThreadCommandBuffer(); @@ -814,7 +814,7 @@ Result FSUSER_CardNorDirectRead_4xIO(u8 commandId, u32 address, u32 size, u8* ou return cmdbuf[1]; } -Result FSUSER_CardNorDirectCpuWriteWithoutVerify(u32 address, u32 size, u8* input) +Result FSUSER_CardNorDirectCpuWriteWithoutVerify(u32 address, u32 size, const void* input) { u32 *cmdbuf = getThreadCommandBuffer(); @@ -929,7 +929,7 @@ Result FSUSER_GetSpecialContentIndex(u16* index, FS_MediaType mediaType, u64 pro return cmdbuf[1]; } -Result FSUSER_GetLegacyRomHeader(FS_MediaType mediaType, u64 programId, u8* header) +Result FSUSER_GetLegacyRomHeader(FS_MediaType mediaType, u64 programId, void* header) { u32 *cmdbuf = getThreadCommandBuffer(); @@ -946,7 +946,7 @@ Result FSUSER_GetLegacyRomHeader(FS_MediaType mediaType, u64 programId, u8* head return cmdbuf[1]; } -Result FSUSER_GetLegacyBannerData(FS_MediaType mediaType, u64 programId, u8* banner) +Result FSUSER_GetLegacyBannerData(FS_MediaType mediaType, u64 programId, void* banner) { u32 *cmdbuf = getThreadCommandBuffer(); @@ -1084,7 +1084,7 @@ Result FSUSER_GetFormatInfo(u32* totalSize, u32* directories, u32* files, bool* return cmdbuf[1]; } -Result FSUSER_GetLegacyRomHeader2(u32 headerSize, FS_MediaType mediaType, u64 programId, u8* header) +Result FSUSER_GetLegacyRomHeader2(u32 headerSize, FS_MediaType mediaType, u64 programId, void* header) { u32 *cmdbuf = getThreadCommandBuffer(); @@ -1183,7 +1183,7 @@ Result FSUSER_FormatSaveData(FS_ArchiveID archiveId, FS_Path path, u32 blocks, u return cmdbuf[1]; } -Result FSUSER_GetLegacySubBannerData(u32 bannerSize, FS_MediaType mediaType, u64 programId, u8* banner) +Result FSUSER_GetLegacySubBannerData(u32 bannerSize, FS_MediaType mediaType, u64 programId, void* banner) { u32 *cmdbuf = getThreadCommandBuffer(); @@ -1246,7 +1246,7 @@ Result FSUSER_UpdateSha256Context(const void* data, u32 inputSize, u8* hash) return cmdbuf[1]; } -Result FSUSER_ReadSpecialFile(u32* bytesRead, u64 fileOffset, u32 size, u8* data) +Result FSUSER_ReadSpecialFile(u32* bytesRead, u64 fileOffset, u32 size, void* data) { u32 *cmdbuf = getThreadCommandBuffer(); diff --git a/libctru/source/services/fspxi.c b/libctru/source/services/fspxi.c new file mode 100644 index 0000000..6c3463e --- /dev/null +++ b/libctru/source/services/fspxi.c @@ -0,0 +1,1386 @@ +#include +#include <3ds/ipc.h> +#include <3ds/result.h> +#include <3ds/services/fspxi.h> +#include <3ds/srv.h> +#include <3ds/svc.h> +#include <3ds/synchronization.h> +#include <3ds/types.h> + +Result FSPXI_OpenFile(Handle serviceHandle, FSPXI_File* out, FSPXI_Archive archive, FS_Path path, u32 flags, u32 attributes) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1, 7, 2); // 0x000101C2 + cmdbuf[1] = 0; // transaction + cmdbuf[2] = (u32) archive; + cmdbuf[3] = (u32)(archive >> 32); + cmdbuf[4] = path.type; + cmdbuf[5] = path.size; + cmdbuf[6] = flags; + cmdbuf[7] = attributes; + cmdbuf[8] = IPC_Desc_PXIBuffer(path.size, 0, true); + cmdbuf[9] = (u32) path.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (out) *out = cmdbuf[2] | ((u64) cmdbuf[3] << 32); + + return (Result) cmdbuf[1]; +} + +Result FSPXI_DeleteFile(Handle serviceHandle, FSPXI_Archive archive, FS_Path path) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x2, 5, 2); // 0x00020142 + cmdbuf[1] = 0; // transaction + cmdbuf[2] = (u32) archive; + cmdbuf[3] = (u32)(archive >> 32); + cmdbuf[4] = path.type; + cmdbuf[5] = path.size; + cmdbuf[6] = IPC_Desc_PXIBuffer(path.size, 0, true); + cmdbuf[7] = (u32) path.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_RenameFile(Handle serviceHandle, FSPXI_Archive srcArchive, FS_Path srcPath, FSPXI_Archive dstArchive, FS_Path dstPath) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x3, 9, 4); // 0x00030244 + cmdbuf[1] = 0; // transaction + cmdbuf[2] = (u32) srcArchive; + cmdbuf[3] = (u32)(srcArchive >> 32); + cmdbuf[4] = srcPath.type; + cmdbuf[5] = srcPath.size; + cmdbuf[6] = (u32) dstArchive; + cmdbuf[7] = (u32)(dstArchive >> 32); + cmdbuf[8] = dstPath.type; + cmdbuf[9] = dstPath.size; + cmdbuf[10] = IPC_Desc_PXIBuffer(srcPath.size, 0, true); + cmdbuf[11] = (u32) srcPath.data; + cmdbuf[12] = IPC_Desc_PXIBuffer(dstPath.size, 1, true); + cmdbuf[13] = (u32) dstPath.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_DeleteDirectory(Handle serviceHandle, FSPXI_Archive archive, FS_Path path) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x4, 5, 2); // 0x00040142 + cmdbuf[1] = 0; // transaction + cmdbuf[2] = (u32) archive; + cmdbuf[3] = (u32)(archive >> 32); + cmdbuf[4] = path.type; + cmdbuf[5] = path.size; + cmdbuf[6] = IPC_Desc_PXIBuffer(path.size, 0, false); + cmdbuf[7] = (u32) path.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CreateFile(Handle serviceHandle, FSPXI_Archive archive, FS_Path path, u32 attributes, u64 fileSize) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x5, 8, 2); // 0x00050202 + cmdbuf[1] = 0; // transaction + cmdbuf[2] = (u32) archive; + cmdbuf[3] = (u32)(archive >> 32); + cmdbuf[4] = path.type; + cmdbuf[5] = path.size; + cmdbuf[6] = attributes; + cmdbuf[7] = (u32)fileSize; + cmdbuf[8] = (u32)(fileSize >> 32); + cmdbuf[8] = IPC_Desc_PXIBuffer(path.size, 0, true); + cmdbuf[9] = (u32) path.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CreateDirectory(Handle serviceHandle, FSPXI_Archive archive, FS_Path path, u32 attributes) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x6, 6, 2); // 0x00060182 + cmdbuf[1] = 0; // transaction + cmdbuf[2] = (u32) archive; + cmdbuf[3] = (u32)(archive >> 32); + cmdbuf[4] = path.type; + cmdbuf[5] = path.size; + cmdbuf[6] = attributes; + cmdbuf[7] = IPC_Desc_PXIBuffer(path.size, 0, true); + cmdbuf[8] = (u32) path.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_RenameDirectory(Handle serviceHandle, FSPXI_Archive srcArchive, FS_Path srcPath, FSPXI_Archive dstArchive, FS_Path dstPath) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x7, 9, 4); // 0x00070244 + cmdbuf[1] = 0; // transaction + cmdbuf[2] = (u32) srcArchive; + cmdbuf[3] = (u32)(srcArchive >> 32); + cmdbuf[4] = srcPath.type; + cmdbuf[5] = srcPath.size; + cmdbuf[6] = (u32) dstArchive; + cmdbuf[7] = (u32)(dstArchive >> 32); + cmdbuf[8] = dstPath.type; + cmdbuf[9] = dstPath.size; + cmdbuf[10] = IPC_Desc_PXIBuffer(srcPath.size, 0, true); + cmdbuf[11] = (u32) srcPath.data; + cmdbuf[12] = IPC_Desc_PXIBuffer(dstPath.size, 1, true); + cmdbuf[13] = (u32) dstPath.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_OpenDirectory(Handle serviceHandle, FSPXI_Directory* out, FSPXI_Archive archive, FS_Path path) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x8, 4, 2); // 0x00080102 + cmdbuf[1] = 0; // transaction + cmdbuf[2] = (u32) archive; + cmdbuf[3] = (u32)(archive >> 32); + cmdbuf[4] = path.type; + cmdbuf[5] = path.size; + cmdbuf[8] = IPC_Desc_PXIBuffer(path.size, 0, true); + cmdbuf[9] = (u32) path.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (out) *out = cmdbuf[2] | ((u64) cmdbuf[3] << 32); + + return (Result) cmdbuf[1]; +} + +Result FSPXI_ReadFile(Handle serviceHandle, FSPXI_File file, u32* bytesRead, u64 offset, void* buffer, u32 size) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x9, 5, 2); // 0x00090142 + cmdbuf[1] = (u32) file; + cmdbuf[2] = (u32)(file >> 32); + cmdbuf[3] = (u32) offset; + cmdbuf[4] = (u32)(offset >> 32); + cmdbuf[5] = size; + cmdbuf[6] = IPC_Desc_PXIBuffer(size, 0, false); + cmdbuf[7] = (u32) buffer; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(bytesRead) *bytesRead = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CalculateFileHashSHA256(Handle serviceHandle, FSPXI_File file, void* buffer, u32 size) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xA, 3, 2); // 0x000A00C2 + cmdbuf[1] = (u32) file; + cmdbuf[2] = (u32)(file >> 32); + cmdbuf[3] = size; + cmdbuf[4] = IPC_Desc_PXIBuffer(size, 0, false); + cmdbuf[5] = (u32) buffer; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_WriteFile(Handle serviceHandle, FSPXI_File file, u32* bytesWritten, u64 offset, const void* buffer, u32 size, u32 flags) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xB,6,2); // 0x000B0182 + cmdbuf[1] = (u32) file; + cmdbuf[2] = (u32)(file >> 32); + cmdbuf[3] = (u32) offset; + cmdbuf[4] = (u32) (offset >> 32); + cmdbuf[5] = flags; + cmdbuf[6] = size; + cmdbuf[7] = IPC_Desc_PXIBuffer(size, 0, true); + cmdbuf[8] = (u32) buffer; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(bytesWritten) *bytesWritten = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CalcSavegameMAC(Handle serviceHandle, FSPXI_File file, const void* inBuffer, u32 inSize, void* outBuffer, u32 outSize) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xC, 4, 4); + cmdbuf[1] = (u32) file; + cmdbuf[2] = (u32)(file >> 32); + cmdbuf[3] = outSize; + cmdbuf[4] = inSize; + cmdbuf[5] = IPC_Desc_PXIBuffer(inSize, 0, true); + cmdbuf[6] = (u32) inBuffer; + cmdbuf[7] = IPC_Desc_PXIBuffer(outSize, 1, false); + cmdbuf[8] = (u32) outBuffer; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetFileSize(Handle serviceHandle, FSPXI_File file, u64* size) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xD, 2, 0); // 0x000D0080 + cmdbuf[1] = (u32) file; + cmdbuf[2] = (u32) (file >> 32); + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (size) *size = cmdbuf[2] | ((u64) cmdbuf[3] << 32); + + return (Result) cmdbuf[1]; +} + +Result FSPXI_SetFileSize(Handle serviceHandle, FSPXI_File file, u64 size) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xE, 4, 0); // 0x000E0100 + cmdbuf[1] = (u32) size; + cmdbuf[2] = (u32) (size >> 32); + cmdbuf[3] = (u32) file; + cmdbuf[4] = (u32) (file >> 32); + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CloseFile(Handle serviceHandle, FSPXI_File file) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xF, 2, 0); // 0x000F0080 + cmdbuf[1] = (u32) file; + cmdbuf[2] = (u32) (file >> 32); + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_ReadDirectory(Handle serviceHandle, FSPXI_Directory directory, u32* entriesRead, u32 entryCount, FS_DirectoryEntry* entries) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x10, 3, 2); // 0x001000C2 + cmdbuf[1] = (u32) directory; + cmdbuf[2] = (u32) (directory >> 32); + cmdbuf[3] = entryCount; + cmdbuf[4] = IPC_Desc_PXIBuffer(sizeof(FS_DirectoryEntry) * entryCount, 0, false); + cmdbuf[5] = (u32) entries; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(entriesRead) *entriesRead = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CloseDirectory(Handle serviceHandle, FSPXI_Directory directory) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x11, 2, 0); // 0x00110080 + cmdbuf[1] = (u32) directory; + cmdbuf[2] = (u32) (directory >> 32); + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_OpenArchive(Handle serviceHandle, FSPXI_Archive* archive, FS_ArchiveID archiveID, FS_Path path) +{ + if (!archive) return -2; + + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x12, 3, 2); + cmdbuf[1] = archiveID; + cmdbuf[2] = path.type; + cmdbuf[3] = path.size; + cmdbuf[4] = IPC_Desc_PXIBuffer(path.size, 0, true); + cmdbuf[5] = (u32)path.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + *archive = cmdbuf[2] | ((u64) cmdbuf[3] << 32); + + return (Result) cmdbuf[1]; +} + +Result FSPXI_HasFile(Handle serviceHandle, FSPXI_Archive archive, bool* out, FS_Path path) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x13, 4, 2); // 0x00130102 + cmdbuf[1] = (u32) archive; + cmdbuf[2] = (u32) (archive >> 32); + cmdbuf[3] = path.type; + cmdbuf[4] = path.size; + cmdbuf[5] = IPC_Desc_PXIBuffer(path.size, 0, true); + cmdbuf[6] = (u32)path.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (out) *out = (bool)cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_HasDirectory(Handle serviceHandle, FSPXI_Archive archive, bool* out, FS_Path path) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x14, 4, 2); // 0x00140102 + cmdbuf[1] = (u32) archive; + cmdbuf[2] = (u32) (archive >> 32); + cmdbuf[3] = path.type; + cmdbuf[4] = path.size; + cmdbuf[5] = IPC_Desc_PXIBuffer(path.size, 0, true); + cmdbuf[6] = (u32)path.data; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (out) *out = (bool)cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CommitSaveData(Handle serviceHandle, FSPXI_Archive archive, u32 id) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x15, 3, 0); // 0x001500C0 + cmdbuf[1] = (u32) archive; + cmdbuf[2] = (u32) (archive >> 32); + cmdbuf[3] = id; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CloseArchive(Handle serviceHandle, FSPXI_Archive archive) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x16, 2, 0); // 0x00160080 + cmdbuf[1] = (u32) archive; + cmdbuf[2] = (u32) (archive >> 32); + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_Unknown0x17(Handle serviceHandle, FSPXI_Archive archive, bool* out) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x17, 2, 0); // 0x00170080 + cmdbuf[1] = (u32) archive; + cmdbuf[2] = (u32) (archive >> 32); + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (out) *out = (bool)cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetCardType(Handle serviceHandle, FS_CardType* out) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x18, 0, 0); // 0x00180000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(out) *out = cmdbuf[2] & 0xFF; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetSdmcArchiveResource(Handle serviceHandle, FS_ArchiveResource* out) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x19, 0, 0); // 0x00190000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(out) + { + out->sectorSize = cmdbuf[2]; + out->clusterSize = cmdbuf[3]; + out->totalClusters = cmdbuf[4]; + out->freeClusters = cmdbuf[5]; + } + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetNandArchiveResource(Handle serviceHandle, FS_ArchiveResource* out) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1A, 0, 0); // 0x001A0000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(out) + { + out->sectorSize = cmdbuf[2]; + out->clusterSize = cmdbuf[3]; + out->totalClusters = cmdbuf[4]; + out->freeClusters = cmdbuf[5]; + } + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetSdmcFatFsError(Handle serviceHandle, u32* out) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1B, 0, 0); // 0x001B0000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(out) *out = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_IsSdmcDetected(Handle serviceHandle, bool* out) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1C, 0, 0); // 0x001C0000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(out) *out = (bool)cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_IsSdmcWritable(Handle serviceHandle, bool* out) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1D, 0, 0); // 0x001D0000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(out) *out = (bool)cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetSdmcCid(Handle serviceHandle, void* out, u32 size) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1E, 0, 0); // 0x001E0000 + cmdbuf[1] = size; + cmdbuf[2] = IPC_Desc_PXIBuffer(size, 0, false); + cmdbuf[3] = (u32) out; + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetNandCid(Handle serviceHandle, void* out, u32 size) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1F, 0, 0); // 0x001F0000 + cmdbuf[1] = size; + cmdbuf[2] = IPC_Desc_PXIBuffer(size, 0, false); + cmdbuf[3] = (u32) out; + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetSdmcSpeedInfo(Handle serviceHandle, u32* out) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x20, 0, 0); // 0x00200000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(out) *out = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetNandSpeedInfo(Handle serviceHandle, u32* out) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x21, 0, 0); // 0x00210000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(out) *out = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetSdmcLog(Handle serviceHandle, void* out, u32 size) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x22, 1, 2); // 0x00220042 + cmdbuf[1] = size; + cmdbuf[2] = IPC_Desc_PXIBuffer(size, 0, false); + cmdbuf[3] = (u32) out; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetNandLog(Handle serviceHandle, void* out, u32 size) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x23, 1, 2); // 0x00230042 + cmdbuf[1] = size; + cmdbuf[2] = IPC_Desc_PXIBuffer(size, 0, false); + cmdbuf[3] = (u32) out; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_ClearSdmcLog(Handle serviceHandle) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x24, 0, 0); // 0x00240000 + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_ClearNandLog(Handle serviceHandle) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x25, 0, 0); // 0x00250000 + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardSlotIsInserted(Handle serviceHandle, bool* inserted) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x26, 0, 0); // 0x00260000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(inserted) *inserted = (bool)cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardSlotPowerOn(Handle serviceHandle, bool* status) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x27, 0, 0); // 0x00270000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(status) *status = (bool)cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardSlotPowerOff(Handle serviceHandle, bool* status) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x28, 0, 0); // 0x00280000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(status) *status = (bool)cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardSlotGetCardIFPowerStatus(Handle serviceHandle, bool* status) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x29, 0, 0); // 0x00290000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(status) *status = (bool)cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardNorDirectCommand(Handle serviceHandle, u8 commandId) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x2A, 1, 0); // 0x002A0040 + cmdbuf[1] = commandId; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardNorDirectCommandWithAddress(Handle serviceHandle, u8 commandId, u32 address) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x2B, 2, 0); // 0x002B0080 + cmdbuf[1] = commandId; + cmdbuf[2] = address; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardNorDirectRead(Handle serviceHandle, u8 commandId, u32 size, void* output) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x2C, 2, 2); // 0x002C0082 + cmdbuf[1] = commandId; + cmdbuf[2] = size; + cmdbuf[3] = IPC_Desc_PXIBuffer(size * sizeof(u32), 0, false); + cmdbuf[4] = (u32) output; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardNorDirectReadWithAddress(Handle serviceHandle, u8 commandId, u32 address, u32 size, void* output) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x2D, 3, 2); // 0x002D00C2 + cmdbuf[1] = commandId; + cmdbuf[2] = address; + cmdbuf[3] = size; + cmdbuf[4] = IPC_Desc_PXIBuffer(size * sizeof(u32), 0, false); + cmdbuf[5] = (u32) output; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardNorDirectWrite(Handle serviceHandle, u8 commandId, u32 size, const void* input) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x2E, 2, 2); // 0x002E0082 + cmdbuf[1] = commandId; + cmdbuf[2] = size; + cmdbuf[3] = IPC_Desc_PXIBuffer(size * sizeof(u32), 0, true); + cmdbuf[4] = (u32) input; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardNorDirectWriteWithAddress(Handle serviceHandle, u8 commandId, u32 address, u32 size, const void* input) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x2F, 3, 2); // 0x002F00C2 + cmdbuf[1] = commandId; + cmdbuf[2] = address; + cmdbuf[3] = size; + cmdbuf[4] = IPC_Desc_PXIBuffer(size * sizeof(u32), 0, true); + cmdbuf[5] = (u32) input; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardNorDirectRead_4xIO(Handle serviceHandle, u8 commandId, u32 address, u32 size, void* output) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x30, 3, 2); // 0x003000C2 + cmdbuf[1] = commandId; + cmdbuf[2] = address; + cmdbuf[3] = size; + cmdbuf[4] = IPC_Desc_PXIBuffer(size * sizeof(u32), 0, false); + cmdbuf[5] = (u32) output; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardNorDirectCpuWriteWithoutVerify(Handle serviceHandle, u32 address, u32 size, const void* input) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x31, 2, 2); // 0x00310082 + cmdbuf[1] = address; + cmdbuf[2] = size; + cmdbuf[3] = IPC_Desc_PXIBuffer(size * sizeof(u32), 0, true); + cmdbuf[4] = (u32) input; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CardNorDirectSectorEraseWithoutVerify(Handle serviceHandle, u32 address) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x32, 1, 0); // 0x00320040 + cmdbuf[1] = address; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetProductInfo(Handle serviceHandle, FS_ProductInfo* info, FSPXI_Archive archive) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x33, 2, 0); // 0x00330080 + cmdbuf[1] = (u32) archive; + cmdbuf[2] = (u32)(archive >> 32); + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(info) memcpy(info, &cmdbuf[2], sizeof(FS_ProductInfo)); + + return (Result) cmdbuf[1]; +} + +Result FSPXI_SetCardSpiBaudrate(Handle serviceHandle, FS_CardSpiBaudRate baudRate) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x34, 1, 0); // 0x00340040 + cmdbuf[1] = baudRate; + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_SetCardSpiBusMode(Handle serviceHandle, FS_CardSpiBusMode busMode) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x35, 1, 0); // 0x00350040 + cmdbuf[1] = busMode; + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_SendInitializeInfoTo9(Handle serviceHandle, u8 unk) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x36, 1, 0); // 0x00360040 + cmdbuf[1] = unk; + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CreateExtSaveData(Handle serviceHandle, FS_ExtSaveDataInfo info) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x37, 4, 0); + memcpy(&cmdbuf[1], &info, sizeof(FS_ExtSaveDataInfo)); + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_DeleteExtSaveData(Handle serviceHandle, FS_ExtSaveDataInfo info) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x38, 4, 0); + memcpy(&cmdbuf[1], &info, sizeof(FS_ExtSaveDataInfo)); + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_EnumerateExtSaveData(Handle serviceHandle, u32* idsWritten, u32 idsSize, FS_MediaType mediaType, u32 idSize, bool shared, u8* ids) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x39, 4, 2); // 0x00390102 + cmdbuf[1] = idsSize; + cmdbuf[2] = mediaType; + cmdbuf[3] = idSize; + cmdbuf[4] = shared; + cmdbuf[5] = IPC_Desc_Buffer(idsSize, IPC_BUFFER_W); + cmdbuf[6] = (u32) ids; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(idsWritten) *idsWritten = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetSpecialContentIndex(Handle serviceHandle, u16* index, FS_MediaType mediaType, u64 programId, FS_SpecialContentType type) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x3A, 4, 0); // 0x003A0100 + cmdbuf[1] = mediaType; + cmdbuf[2] = (u32) programId; + cmdbuf[3] = (u32) (programId >> 32); + cmdbuf[4] = type; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(index) *index = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetLegacyRomHeader(Handle serviceHandle, FS_MediaType mediaType, u64 programId, void* header) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x3B, 3, 2); // 0x003B00C2 + cmdbuf[1] = mediaType; + cmdbuf[2] = (u32) programId; + cmdbuf[3] = (u32) (programId >> 32); + cmdbuf[4] = IPC_Desc_PXIBuffer(0x378, 0, false); + cmdbuf[5] = (u32) header; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetLegacyBannerData(Handle serviceHandle, FS_MediaType mediaType, u64 programId, void* banner, u8 unk) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x3C, 4, 2); // 0x003C0102 + cmdbuf[1] = mediaType; + cmdbuf[2] = (u32) programId; + cmdbuf[3] = (u32) (programId >> 32); + cmdbuf[4] = unk; + cmdbuf[5] = IPC_Desc_PXIBuffer(0x23c0, 0, false); + cmdbuf[6] = (u32) banner; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_FormatCardNorDevice(Handle serviceHandle, u32 unk) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x3D, 1, 0); // 0x003D0040 + cmdbuf[1] = unk; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_DeleteSdmcRoot(Handle serviceHandle) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x3E, 0, 0); // 0x003E0000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_DeleteAllExtSaveDataOnNand(Handle serviceHandle) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x3F, 1, 0); // 0x003F0000 + cmdbuf[1] = 0; // Transaction + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_InitializeCtrFilesystem(Handle serviceHandle) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x40, 0, 0); // 0x00400000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_CreateSeed(Handle serviceHandle) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x41, 0, 0); // 0x00410000 + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetSdmcCtrRootPath(Handle serviceHandle, u16* out, u32 length) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x42, 1, 2); // 0x00420042 + cmdbuf[1] = length; + cmdbuf[2] = IPC_Desc_PXIBuffer(length, 0, false); + cmdbuf[3] = (u32) out; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetArchiveResource(Handle serviceHandle, FS_ArchiveResource* archiveResource, FS_SystemMediaType mediaType) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x43, 1, 0); // 0x00430040 + cmdbuf[1] = mediaType; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + memcpy(archiveResource, &cmdbuf[2], sizeof(FS_ArchiveResource)); + + return (Result) cmdbuf[1]; +} + +Result FSPXI_ExportIntegrityVerificationSeed(Handle serviceHandle, FS_IntegrityVerificationSeed* seed) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x44, 0, 2); // 0x00440002 + cmdbuf[1] = IPC_Desc_PXIBuffer(0x130, 0, false); + cmdbuf[2] = (u32)seed; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_ImportIntegrityVerificationSeed(Handle serviceHandle, const FS_IntegrityVerificationSeed* seed) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x45, 0, 2); // 0x00450002 + cmdbuf[1] = IPC_Desc_PXIBuffer(0x130, 0, true); + cmdbuf[2] = (u32)seed; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetLegacySubBannerData(Handle serviceHandle, u32 bannerSize, FS_MediaType mediaType, u64 programId, void* banner) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x46, 4, 2); // 0x00460102 + cmdbuf[1] = bannerSize; + cmdbuf[2] = mediaType; + cmdbuf[3] = (u32) programId; + cmdbuf[4] = (u32) (programId >> 32); + cmdbuf[5] = IPC_Desc_PXIBuffer(bannerSize, 0, false); + cmdbuf[6] = (u32) banner; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GenerateRandomBytes(Handle serviceHandle, void* buf, u32 size) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x47, 1, 2); // 0x00470042 + cmdbuf[1] = size; + cmdbuf[2] = IPC_Desc_PXIBuffer(size, 0, false); + cmdbuf[3] = (u32) buf; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetFileLastModified(Handle serviceHandle, FSPXI_Archive archive, u64* out, const u16* path, u32 size) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x48, 3, 2); // 0x004800C2 + cmdbuf[1] = (u32) archive; + cmdbuf[2] = (u32) (archive >> 32); + cmdbuf[3] = size; + cmdbuf[4] = IPC_Desc_PXIBuffer(size, 0, true); + cmdbuf[5] = (u32) path; + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (out) *out = cmdbuf[2] | ((u64) cmdbuf[3] << 32); + + return (Result) cmdbuf[1]; +} + +Result FSPXI_ReadSpecialFile(Handle serviceHandle, u32* bytesRead, u64 fileOffset, u32 size, void* data) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x49, 4, 2); // 0x00490102 + cmdbuf[1] = 0; + cmdbuf[2] = (u32) fileOffset; + cmdbuf[3] = (u32) (fileOffset >> 32); + cmdbuf[4] = size; + cmdbuf[5] = IPC_Desc_PXIBuffer(size, 0, false); + cmdbuf[6] = (u32) data; + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (bytesRead) *bytesRead = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_GetSpecialFileSize(Handle serviceHandle, u64* fileSize) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x4A, 1, 0); // 0x004A0040 + cmdbuf[1] = 0; // Must be 0 + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (fileSize) *fileSize = cmdbuf[2] | ((u64) cmdbuf[3] << 32); + + return (Result) cmdbuf[1]; +} + +Result FSPXI_StartDeviceMoveAsSource(Handle serviceHandle, FS_DeviceMoveContext* context) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x4B, 0, 0); // 0x004B0000 + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if(context) memcpy(context, &cmdbuf[2], sizeof(FS_DeviceMoveContext)); + + return (Result) cmdbuf[1]; +} + +Result FSPXI_StartDeviceMoveAsDestination(Handle serviceHandle, FS_DeviceMoveContext context, bool clear) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x4C, 9, 0); // 0x004C0240 + memcpy(&cmdbuf[1], &context, sizeof(FS_DeviceMoveContext)); + cmdbuf[9] = clear; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_ReadFileSHA256(Handle serviceHandle, FSPXI_File file, u32* bytesRead, u64 offset, void* readBuffer, u32 readBufferSize, void* hashtable, u32 hashtableSize, u32 unk) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x4D, 7, 4); // 0x004D01C4 + cmdbuf[1] = (u32) file; + cmdbuf[2] = (u32) (file >> 32); + cmdbuf[3] = (u32) offset; + cmdbuf[4] = (u32) (offset >> 32); + cmdbuf[5] = readBufferSize; + cmdbuf[6] = unk; + cmdbuf[7] = hashtableSize; + cmdbuf[8] = IPC_Desc_PXIBuffer(hashtableSize, 0, false); + cmdbuf[9] = (u32) hashtable; + cmdbuf[10] = IPC_Desc_PXIBuffer(readBufferSize, 1, false); + cmdbuf[11] = (u32) readBuffer; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (bytesRead) *bytesRead = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_WriteFileSHA256(Handle serviceHandle, FSPXI_File file, u32* bytesWritten, u64 offset, const void* writeBuffer, u32 writeBufferSize, void* hashtable, u32 hashtableSize, u32 unk1, u32 unk2) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x4E, 8, 4); // 0x004E0204 + cmdbuf[1] = (u32) file; + cmdbuf[2] = (u32) (file >> 32); + cmdbuf[3] = (u32) offset; + cmdbuf[4] = (u32) (offset >> 32); + cmdbuf[5] = writeBufferSize; + cmdbuf[6] = unk1; + cmdbuf[7] = hashtableSize; + cmdbuf[8] = unk2; + cmdbuf[9] = IPC_Desc_PXIBuffer(hashtableSize, 0, true); + cmdbuf[10] = (u32) hashtable; + cmdbuf[11] = IPC_Desc_PXIBuffer(writeBufferSize, 1, false); + cmdbuf[12] = (u32) writeBuffer; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (bytesWritten) *bytesWritten = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_SetCtrCardLatencyParameter(Handle serviceHandle, u64 latency) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x4F, 2, 0); // 0x004F0080 + cmdbuf[1] = (u32) latency; + cmdbuf[2] = (u32) (latency >> 32); + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_SetPriority(Handle serviceHandle, u32 priority) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x50, 1, 0); // 0x00500040 + cmdbuf[1] = priority; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_SwitchCleanupInvalidSaveData(Handle serviceHandle, bool enable) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x51, 1, 0); // 0x00500040 + cmdbuf[1] = enable; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_EnumerateSystemSaveData(Handle serviceHandle, u32* idsWritten, u32 idsSize, u32* ids) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x54, 1, 2); // 0x00540042 + cmdbuf[1] = idsSize; + cmdbuf[2] = IPC_Desc_PXIBuffer(idsSize, 0, false); + cmdbuf[3] = (u32) ids; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + if (idsWritten) *idsWritten = cmdbuf[2]; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_ReadNandReport(Handle serviceHandle, void* buffer, u32 size, u32 unk) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x55, 2, 2); // 0x00550082 + cmdbuf[1] = size; + cmdbuf[2] = unk; + cmdbuf[3] = IPC_Desc_PXIBuffer(size, 0, false); + cmdbuf[4] = (u32) buffer; + + if(R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + return (Result) cmdbuf[1]; +} + +Result FSPXI_Unknown0x56(Handle serviceHandle, u32 out[4], FS_Archive archive, FS_Path path) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x56, 4, 2); // 0x00560102 + cmdbuf[1] = (u32) archive; + cmdbuf[2] = (u32) (archive >> 32); + cmdbuf[3] = path.type; + cmdbuf[4] = path.size; + cmdbuf[5] = IPC_Desc_PXIBuffer(path.size, 0, true); + cmdbuf[6] = (u32)path.data; + + if (R_FAILED(ret = svcSendSyncRequest(serviceHandle))) return ret; + + out[0] = cmdbuf[2]; + out[1] = cmdbuf[3]; + out[2] = cmdbuf[4]; + out[3] = cmdbuf[5]; + + return (Result) cmdbuf[1]; +}