mirror of
https://github.com/switchbrew/libnx.git
synced 2025-07-04 02:22:15 +02:00
Merge branch 'master' into gpu
This commit is contained in:
commit
282a5ad904
@ -22,5 +22,10 @@
|
||||
## Functions
|
||||
`modulenameFunctionName`
|
||||
|
||||
### Submodule function naming
|
||||
Singletons use names like smInitialize/smExit
|
||||
|
||||
Objects use names like tmemCreate/tmemClose
|
||||
|
||||
## Macros
|
||||
`LIKE_THIS`
|
||||
|
@ -5,7 +5,3 @@ Based on libctru.
|
||||
|
||||
# Install instructions
|
||||
See [Switchbrew](http://switchbrew.org/index.php?title=Setting_up_Development_Environment).
|
||||
|
||||
# Icon
|
||||
|
||||
`nx/default_icon.jpg` is based on the icon by [Sweet Farm from the Noun Project](https://thenounproject.com/term/nintendo-switch/694750/).
|
||||
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 6.1 KiB |
@ -12,11 +12,14 @@ extern "C" {
|
||||
#include "switch/types.h"
|
||||
#include "switch/result.h"
|
||||
|
||||
#include "switch/nro.h"
|
||||
|
||||
#include "switch/kernel/svc.h"
|
||||
#include "switch/kernel/tmem.h"
|
||||
#include "switch/kernel/shmem.h"
|
||||
#include "switch/kernel/mutex.h"
|
||||
#include "switch/kernel/rwlock.h"
|
||||
#include "switch/kernel/condvar.h"
|
||||
#include "switch/kernel/thread.h"
|
||||
#include "switch/kernel/virtmem.h"
|
||||
#include "switch/kernel/detect.h"
|
||||
@ -35,12 +38,14 @@ extern "C" {
|
||||
#include "switch/services/audout.h"
|
||||
#include "switch/services/bsd.h"
|
||||
#include "switch/services/fatal.h"
|
||||
#include "switch/services/time.h"
|
||||
#include "switch/services/usb.h"
|
||||
#include "switch/services/hid.h"
|
||||
#include "switch/services/irs.h"
|
||||
#include "switch/services/vi.h"
|
||||
#include "switch/services/nv.h"
|
||||
#include "switch/services/pm.h"
|
||||
#include "switch/services/set.h"
|
||||
|
||||
#include "switch/display/gfx.h"
|
||||
#include "switch/display/binder.h"
|
||||
@ -65,6 +70,7 @@ extern "C" {
|
||||
#include "switch/runtime/devices/console.h"
|
||||
#include "switch/runtime/devices/usb_comms.h"
|
||||
#include "switch/runtime/devices/fs_dev.h"
|
||||
#include "switch/runtime/devices/romfs_dev.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
/// Same as \ref RGBA8 except with alpha=0xff.
|
||||
#define RGBA8_MAXALPHA(r,g,b) RGBA8(r,g,b,0xff)
|
||||
|
||||
/// GfxMode set by \ref gfxSetMode. The default is GfxMode_LinearDouble. Note that the text-console (see console.h) sets this to GfxMode_TiledSingle.
|
||||
/// GfxMode set by \ref gfxSetMode. The default is GfxMode_LinearDouble. Note that the text-console (see console.h) sets this to GfxMode_TiledDouble.
|
||||
typedef enum
|
||||
{
|
||||
GfxMode_TiledSingle, ///< Single-buffering with raw tiled (block-linear) framebuffer.
|
||||
@ -22,6 +22,8 @@ typedef enum
|
||||
GfxMode_LinearDouble ///< Double-buffering with linear framebuffer, which is transferred to the actual framebuffer by \ref gfxFlushBuffers().
|
||||
} GfxMode;
|
||||
|
||||
/// Framebuffer pixel-format is RGBA8888, there's no known way to change this.
|
||||
|
||||
/**
|
||||
* @brief Initializes the graphics subsystem.
|
||||
* @warning Do not use \ref viInitialize when using this function.
|
||||
@ -83,6 +85,12 @@ size_t gfxGetFramebufferSize(void);
|
||||
/// Sets the \ref GfxMode.
|
||||
void gfxSetMode(GfxMode mode);
|
||||
|
||||
/// Controls whether a vertical-flip is done when determining the pixel-offset within the actual framebuffer. By default this is enabled.
|
||||
void gfxSetDrawFlip(bool flip);
|
||||
|
||||
/// Configures transform. See the NATIVE_WINDOW_TRANSFORM_* enums in buffer_producer.h. The default is NATIVE_WINDOW_TRANSFORM_FLIP_V.
|
||||
void gfxConfigureTransform(u32 transform);
|
||||
|
||||
/// Flushes the framebuffer in the data cache. When \ref GfxMode is GfxMode_LinearDouble, this also transfers the linear-framebuffer to the actual framebuffer.
|
||||
void gfxFlushBuffers(void);
|
||||
|
||||
@ -94,10 +102,11 @@ static inline u32 gfxGetFramebufferDisplayOffset(u32 x, u32 y) {
|
||||
|
||||
extern size_t g_gfx_framebuf_aligned_width;
|
||||
extern size_t g_gfx_framebuf_display_height;
|
||||
extern bool g_gfx_drawflip;
|
||||
|
||||
//if (x >= g_gfx_framebuf_width || y >= g_gfx_framebuf_display_height) return (gfxGetFramebufferSize()-4)/4;//Return the last pixel-offset in the buffer, the data located here is not displayed due to alignment. (Disabled for perf)
|
||||
|
||||
y = g_gfx_framebuf_display_height-1-y;
|
||||
if (g_gfx_drawflip) y = g_gfx_framebuf_display_height-1-y;
|
||||
|
||||
tmp_pos = ((y & 127) / 16) + (x/16*8) + ((y/16/8)*(g_gfx_framebuf_aligned_width/16*8));
|
||||
tmp_pos *= 16*16 * 4;
|
||||
|
54
nx/include/switch/nro.h
Normal file
54
nx/include/switch/nro.h
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @file nro.h
|
||||
* @brief NRO headers.
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define NROHEADER_MAGIC 0x304f524e
|
||||
|
||||
#define NROASSETHEADER_MAGIC 0x54455341
|
||||
#define NROASSETHEADER_VERSION 0
|
||||
|
||||
/// Entry for each segment in the codebin.
|
||||
typedef struct {
|
||||
u32 file_off;
|
||||
u32 size;
|
||||
} NroSegment;
|
||||
|
||||
/// Offset 0x0 in the NRO.
|
||||
typedef struct {
|
||||
u32 unused;
|
||||
u32 mod_offset;
|
||||
u8 padding[8];
|
||||
} NroStart;
|
||||
|
||||
/// This follows NroStart, the actual nro-header.
|
||||
typedef struct {
|
||||
u32 magic;
|
||||
u32 unk1;
|
||||
u32 size;
|
||||
u32 unk2;
|
||||
NroSegment segments[3];
|
||||
u32 bss_size;
|
||||
u32 unk3;
|
||||
u8 build_id[0x20];
|
||||
u8 padding[0x20];
|
||||
} NroHeader;
|
||||
|
||||
/// Custom asset section.
|
||||
typedef struct {
|
||||
u64 offset;
|
||||
u64 size;
|
||||
} NroAssetSection;
|
||||
|
||||
/// Custom asset header.
|
||||
typedef struct {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
NroAssetSection icon;
|
||||
NroAssetSection nacp;
|
||||
NroAssetSection romfs;
|
||||
} NroAssetHeader;
|
||||
|
@ -64,6 +64,7 @@ enum {
|
||||
LibnxError_JitUnavailable,
|
||||
LibnxError_WeirdKernel,
|
||||
LibnxError_IncompatSysVer,
|
||||
LibnxError_InitFail_Time,
|
||||
};
|
||||
|
||||
/// libnx nvidia error codes
|
||||
|
@ -37,7 +37,7 @@ typedef bool(*ConsolePrint)(void* con, int c);
|
||||
/// A font struct for the console.
|
||||
typedef struct ConsoleFont
|
||||
{
|
||||
u8* gfx; ///< A pointer to the font graphics
|
||||
u16* gfx; ///< A pointer to the font graphics
|
||||
u16 asciiOffset; ///< Offset to the first valid character in the font table
|
||||
u16 numChars; ///< Number of characters in the font graphics
|
||||
}ConsoleFont;
|
||||
@ -51,18 +51,18 @@ typedef struct ConsoleFont
|
||||
* {
|
||||
* //Font:
|
||||
* {
|
||||
* (u8*)default_font_bin, //font gfx
|
||||
* (u16*)default_font_bin, //font gfx
|
||||
* 0, //first ascii character in the set
|
||||
* 128, //number of characters in the font set
|
||||
* },
|
||||
* 0,0, //cursorX cursorY
|
||||
* 0,0, //prevcursorX prevcursorY
|
||||
* 160, //console width
|
||||
* 90, //console height
|
||||
* 80, //console width
|
||||
* 45, //console height
|
||||
* 0, //window x
|
||||
* 0, //window y
|
||||
* 160, //window width
|
||||
* 90, //window height
|
||||
* 80, //window width
|
||||
* 45, //window height
|
||||
* 3, //tab size
|
||||
* 0, //font character offset
|
||||
* 0, //print callback
|
||||
@ -75,6 +75,7 @@ typedef struct PrintConsole
|
||||
ConsoleFont font; ///< Font of the console
|
||||
|
||||
u32 *frameBuffer; ///< Framebuffer address
|
||||
u32 *frameBuffer2; ///< Framebuffer address
|
||||
|
||||
int cursorX; ///< Current X location of the cursor (as a tile offset by default)
|
||||
int cursorY; ///< Current Y location of the cursor (as a tile offset by default)
|
||||
|
@ -38,3 +38,6 @@ int fsdevUnmountDevice(const char *name);
|
||||
/// Uses fsFsCommit() with the specified device. This must be used after any savedata-write operations(not just file-write).
|
||||
/// This is not used automatically at device unmount.
|
||||
Result fsdevCommitDevice(const char *name);
|
||||
|
||||
/// Returns the FsFileSystem for the default device (SD card), if mounted. Used internally by romfs_dev.
|
||||
FsFileSystem* fsdevGetDefaultFileSystem(void);
|
||||
|
@ -66,7 +66,7 @@ static inline Result romfsInit(void)
|
||||
|
||||
/**
|
||||
* @brief Mounts RomFS from an open file.
|
||||
* @param file Handle of the RomFS file.
|
||||
* @param file FsFile of the RomFS image.
|
||||
* @param offset Offset of the RomFS within the file.
|
||||
* @param mount Output mount handle
|
||||
*/
|
||||
@ -76,6 +76,18 @@ static inline Result romfsInitFromFile(FsFile file, u64 offset)
|
||||
return romfsMountFromFile(file, offset, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mounts RomFS from an open storage.
|
||||
* @param storage FsStorage of the RomFS image.
|
||||
* @param offset Offset of the RomFS within the storage.
|
||||
* @param mount Output mount handle
|
||||
*/
|
||||
Result romfsMountFromStorage(FsStorage storage, u64 offset, struct romfs_mount **mount);
|
||||
static inline Result romfsInitFromStorage(FsStorage storage, u64 offset)
|
||||
{
|
||||
return romfsMountFromStorage(storage, offset, NULL);
|
||||
}
|
||||
|
||||
/// Bind the RomFS mount
|
||||
Result romfsBind(struct romfs_mount *mount);
|
||||
|
||||
|
@ -51,6 +51,8 @@ Result appletGetAppletResourceUserId(u64 *out);
|
||||
void appletNotifyRunning(u8 *out);
|
||||
Result appletCreateManagedDisplayLayer(u64 *out);
|
||||
|
||||
Result appletGetDesiredLanguage(u64 *LanguageCode);
|
||||
|
||||
/**
|
||||
* @brief Controls whether screenshot-capture is allowed.
|
||||
* @param val 0 = disable, 1 = enable.
|
||||
|
@ -1,6 +1,7 @@
|
||||
/**
|
||||
* @file fs.h
|
||||
* @brief Filesystem (fsp-srv) service IPC wrapper.
|
||||
* Normally applications should just use standard stdio not FS-serv directly. However this can be used if obtaining a FsFileSystem, FsFile, or FsStorage, for mounting with fs_dev/romfs_dev.
|
||||
* @author plutoo
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
@ -91,8 +92,11 @@ void fsExit(void);
|
||||
|
||||
Service* fsGetServiceSession(void);
|
||||
|
||||
/// Do not call this directly, see fs_dev.h.
|
||||
Result fsMountSdcard(FsFileSystem* out);
|
||||
|
||||
Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save);
|
||||
Result fsOpenDataStorageByCurrentProcess(FsStorage* out);
|
||||
// todo: Rest of commands here
|
||||
|
||||
/// FsFileSystem can be mounted with fs_dev for use with stdio, see fs_dev.h.
|
||||
@ -130,4 +134,6 @@ Result fsDirRead(FsDir* d, u64 inval, size_t* total_entries, size_t max_entries,
|
||||
Result fsDirGetEntryCount(FsDir* d, u64* count);
|
||||
void fsDirClose(FsDir* d);
|
||||
|
||||
// todo: IStorage
|
||||
// IStorage
|
||||
Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len);
|
||||
void fsStorageClose(FsStorage* s);
|
||||
|
@ -328,6 +328,16 @@ typedef struct JoystickPosition
|
||||
s32 dy;
|
||||
} JoystickPosition;
|
||||
|
||||
typedef struct MousePosition
|
||||
{
|
||||
u32 x;
|
||||
u32 y;
|
||||
u32 velocityX;
|
||||
u32 velocityY;
|
||||
u32 scrollVelocityX;
|
||||
u32 scrollVelocityY;
|
||||
} MousePosition;
|
||||
|
||||
#define JOYSTICK_MAX (0x8000)
|
||||
#define JOYSTICK_MIN (-0x8000)
|
||||
|
||||
@ -399,12 +409,7 @@ typedef struct HidMouseEntry
|
||||
{
|
||||
u64 timestamp;
|
||||
u64 timestamp_2;
|
||||
u32 x;
|
||||
u32 y;
|
||||
u32 velocityX;
|
||||
u32 velocityY;
|
||||
u32 scrollVelocityX;
|
||||
u32 scrollVelocityY;
|
||||
MousePosition position;
|
||||
u64 buttons;
|
||||
} HidMouseEntry;
|
||||
static_assert(sizeof(HidMouseEntry) == 0x30, "Hid mouse entry structure has incorrect size");
|
||||
@ -552,6 +557,7 @@ u64 hidKeysUp(HidControllerID id);
|
||||
u64 hidMouseButtonsHeld(void);
|
||||
u64 hidMouseButtonsDown(void);
|
||||
u64 hidMouseButtonsUp(void);
|
||||
void hidMouseRead(MousePosition *pos);
|
||||
|
||||
bool hidKeyboardModifierHeld(HidKeyboardModifier modifier);
|
||||
bool hidKeyboardModifierDown(HidKeyboardModifier modifier);
|
||||
|
67
nx/include/switch/services/set.h
Normal file
67
nx/include/switch/services/set.h
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @file set.h
|
||||
* @brief Settings services IPC wrapper.
|
||||
* @author plutoo
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#include "../result.h"
|
||||
|
||||
typedef enum {
|
||||
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;
|
||||
|
||||
Result setInitialize(void);
|
||||
void setExit(void);
|
||||
|
||||
/// Converts LanguageCode to Language.
|
||||
Result setMakeLanguage(u64 LanguageCode, s32 *Language);
|
||||
|
||||
/// Converts Language to LanguageCode.
|
||||
Result setMakeLanguageCode(s32 Language, u64 *LanguageCode);
|
||||
|
||||
/// Gets the current system LanguageCode.
|
||||
/// Normally this should be used instead of \ref setGetLanguageCode.
|
||||
/// LanguageCode is a string, see here: http://switchbrew.org/index.php?title=Settings_services#LanguageCode
|
||||
Result setGetSystemLanguage(u64 *LanguageCode);
|
||||
|
||||
/// Gets the current LanguageCode, \ref setGetSystemLanguage should be used instead normally.
|
||||
Result setGetLanguageCode(u64 *LanguageCode);
|
||||
|
||||
/// Gets available LanguageCodes.
|
||||
/// On system-version <4.0.0, max_entries is set to the output from \ref setGetAvailableLanguageCodeCount if max_entries is larger than that.
|
||||
Result setGetAvailableLanguageCodes(s32 *total_entries, u64 *LanguageCodes, size_t max_entries);
|
||||
|
||||
/// Gets total available LanguageCodes.
|
||||
/// Output total is overridden with value 0 if the total is <0.
|
||||
Result setGetAvailableLanguageCodeCount(s32 *total);
|
||||
|
||||
/// Gets the RegionCode.
|
||||
Result setGetRegionCode(s32 *RegionCode);
|
||||
|
||||
Result setsysInitialize(void);
|
||||
void setsysExit(void);
|
||||
|
||||
/// Gets the current system theme.
|
||||
Result setsysGetColorSetId(ColorSetId* out);
|
33
nx/include/switch/services/time.h
Normal file
33
nx/include/switch/services/time.h
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file time.h
|
||||
* @brief Time services IPC wrapper.
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
|
||||
/// Time clock type.
|
||||
typedef enum {
|
||||
TimeType_UserSystemClock,
|
||||
TimeType_NetworkSystemClock,
|
||||
TimeType_LocalSystemClock,
|
||||
TimeType_Default = TimeType_NetworkSystemClock,
|
||||
} TimeType;
|
||||
|
||||
Result timeInitialize(void);
|
||||
void timeExit(void);
|
||||
|
||||
Service* timeGetSessionService(void);
|
||||
|
||||
Result timeGetCurrentTime(TimeType type, u64 *timestamp);
|
||||
|
||||
/**
|
||||
* @brief Sets the time for the specified clock.
|
||||
* @param[in] type Clock to use.
|
||||
* @param[in] timestamp POSIX UTC timestamp.
|
||||
* @return Result code.
|
||||
*/
|
||||
Result timeSetCurrentTime(TimeType type, u64 timestamp);
|
@ -34,12 +34,16 @@ static GfxMode g_gfxMode = GfxMode_LinearDouble;
|
||||
|
||||
static u8 *g_gfxFramebufLinear;
|
||||
|
||||
static s32 g_gfxPixelFormat = 0;
|
||||
|
||||
size_t g_gfx_framebuf_width=0, g_gfx_framebuf_aligned_width=0;
|
||||
size_t g_gfx_framebuf_height=0, g_gfx_framebuf_aligned_height=0;
|
||||
size_t g_gfx_framebuf_display_width=0, g_gfx_framebuf_display_height=0;
|
||||
size_t g_gfx_singleframebuf_size=0;
|
||||
size_t g_gfx_singleframebuf_linear_size=0;
|
||||
|
||||
bool g_gfx_drawflip = true;
|
||||
|
||||
static AppletHookCookie g_gfx_autoresolution_applethookcookie;
|
||||
static bool g_gfx_autoresolution_enabled;
|
||||
|
||||
@ -55,7 +59,6 @@ extern nvioctl_fence g_nvgfx_nvhostgpu_gpfifo_fence;
|
||||
|
||||
//static Result _gfxGetDisplayResolution(u64 *width, u64 *height);
|
||||
|
||||
// TODO: Let the user configure some of this?
|
||||
static BqQueueBufferInput g_gfxQueueBufferData = {
|
||||
.timestamp = 0x0,
|
||||
.isAutoTimestamp = 0x1,
|
||||
@ -135,7 +138,7 @@ static Result _gfxDequeueBuffer(void) {
|
||||
|
||||
memcpy(&tmp_fence, fence, sizeof(BqFence));//Offical sw waits on the fence from the previous DequeueBuffer call. Using the fence from the current DequeueBuffer call results in nvgfxEventWait() failing.
|
||||
|
||||
rc = bqDequeueBuffer(async, g_gfx_framebuf_width, g_gfx_framebuf_height, 0, 0x300, &g_gfxCurrentProducerBuffer, fence);
|
||||
rc = bqDequeueBuffer(async, g_gfx_framebuf_width, g_gfx_framebuf_height, g_gfxPixelFormat, 0x300, &g_gfxCurrentProducerBuffer, fence);
|
||||
|
||||
//Only run nvgfxEventWait when the fence is valid and the id is not NO_FENCE.
|
||||
if (R_SUCCEEDED(rc) && tmp_fence.is_valid && tmp_fence.nv_fences[0].id!=0xffffffff) rc = nvgfxEventWait(tmp_fence.nv_fences[0].id, tmp_fence.nv_fences[0].value, -1);
|
||||
@ -178,6 +181,10 @@ static Result _gfxInit(ViServiceType servicetype, const char *DisplayName, u32 L
|
||||
g_gfxFramebufSize = 0;
|
||||
g_gfxMode = GfxMode_LinearDouble;
|
||||
|
||||
g_gfx_drawflip = true;
|
||||
g_gfxQueueBufferData.transform = NATIVE_WINDOW_TRANSFORM_FLIP_V;
|
||||
g_gfxPixelFormat = 0;
|
||||
|
||||
memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested));
|
||||
memset(&g_gfx_DequeueBuffer_fence, 0, sizeof(g_gfx_DequeueBuffer_fence));
|
||||
|
||||
@ -538,6 +545,18 @@ void gfxSetMode(GfxMode mode) {
|
||||
g_gfxMode = mode;
|
||||
}
|
||||
|
||||
void gfxSetDrawFlip(bool flip) {
|
||||
g_gfx_drawflip = flip;
|
||||
}
|
||||
|
||||
void gfxConfigureTransform(u32 transform) {
|
||||
g_gfxQueueBufferData.transform = transform;
|
||||
}
|
||||
|
||||
/*void gfxSetPixelFormat(s32 format) {
|
||||
g_gfxPixelFormat = format;
|
||||
}*/
|
||||
|
||||
void gfxFlushBuffers(void) {
|
||||
u32 *actual_framebuf = (u32*)&g_gfxFramebuf[g_gfxCurrentBuffer*g_gfx_singleframebuf_size];
|
||||
|
||||
|
@ -13,7 +13,7 @@ void condvarInit(CondVar* c, Mutex* m) {
|
||||
Result condvarWaitTimeout(CondVar* c, u64 timeout) {
|
||||
Result rc;
|
||||
|
||||
rc = svcWaitProcessWideKeyAtomic(&c->tag, (u32*) c->mutex, getThreadVars()->handle, timeout);
|
||||
rc = svcWaitProcessWideKeyAtomic((u32*) c->mutex, &c->tag, getThreadVars()->handle, timeout);
|
||||
|
||||
// On timeout, we need to acquire it manually.
|
||||
if (rc == 0xEA01)
|
||||
|
@ -42,19 +42,20 @@ PrintConsole defaultConsole =
|
||||
{
|
||||
//Font:
|
||||
{
|
||||
(u8*)default_font_bin, //font gfx
|
||||
(u16*)default_font_bin, //font gfx
|
||||
0, //first ascii character in the set
|
||||
256 //number of characters in the font set
|
||||
},
|
||||
(u32*)NULL,
|
||||
(u32*)NULL,
|
||||
0,0, //cursorX cursorY
|
||||
0,0, //prevcursorX prevcursorY
|
||||
160, //console width
|
||||
90, //console height
|
||||
80, //console width
|
||||
45, //console height
|
||||
0, //window x
|
||||
0, //window y
|
||||
160, //window width
|
||||
90, //window height
|
||||
80, //window width
|
||||
45, //window height
|
||||
3, //tab size
|
||||
7, // foreground color
|
||||
0, // background color
|
||||
@ -123,6 +124,8 @@ static void consoleCls(char mode) {
|
||||
}
|
||||
}
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
gfxWaitForVsync();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
static void consoleClearLine(char mode) {
|
||||
@ -176,6 +179,8 @@ static void consoleClearLine(char mode) {
|
||||
}
|
||||
}
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
gfxWaitForVsync();
|
||||
}
|
||||
|
||||
|
||||
@ -547,12 +552,15 @@ PrintConsole* consoleInit(PrintConsole* console) {
|
||||
|
||||
console->consoleInitialised = 1;
|
||||
|
||||
gfxSetMode(GfxMode_TiledSingle);
|
||||
gfxFlushBuffers();
|
||||
gfxWaitForVsync();
|
||||
gfxSetMode(GfxMode_TiledDouble);
|
||||
|
||||
console->frameBuffer = (u32*)gfxGetFramebuffer(NULL, NULL);
|
||||
gfxSwapBuffers();
|
||||
console->frameBuffer2 = (u32*)gfxGetFramebuffer(NULL, NULL);
|
||||
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
gfxWaitForVsync();
|
||||
|
||||
consoleCls('2');
|
||||
|
||||
@ -615,15 +623,18 @@ static void newRow(void) {
|
||||
int i,j;
|
||||
u32 x, y;
|
||||
|
||||
x = currentConsole->windowX * 8;
|
||||
y = currentConsole->windowY * 8;
|
||||
x = currentConsole->windowX * 16;
|
||||
y = currentConsole->windowY * 16;
|
||||
|
||||
for (i=0; i<currentConsole->windowWidth*8; i++) {
|
||||
for (i=0; i<currentConsole->windowWidth*16; i++) {
|
||||
u32 *from;
|
||||
u32 *to;
|
||||
for (j=0;j<(currentConsole->windowHeight-1)*8;j++) {
|
||||
for (j=0;j<(currentConsole->windowHeight-1)*16;j++) {
|
||||
to = ¤tConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + j)];
|
||||
from = ¤tConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + 8 + j)];
|
||||
from = ¤tConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + 16 + j)];
|
||||
*to = *from;
|
||||
to = ¤tConsole->frameBuffer2[gfxGetFramebufferDisplayOffset(x + i, y + j)];
|
||||
from = ¤tConsole->frameBuffer2[gfxGetFramebufferDisplayOffset(x + i, y + 16 + j)];
|
||||
*to = *from;
|
||||
}
|
||||
}
|
||||
@ -637,7 +648,7 @@ void consoleDrawChar(int c) {
|
||||
c -= currentConsole->font.asciiOffset;
|
||||
if ( c < 0 || c > currentConsole->font.numChars ) return;
|
||||
|
||||
u8 *fontdata = currentConsole->font.gfx + (8 * c);
|
||||
u16 *fontdata = currentConsole->font.gfx + (16 * c);
|
||||
|
||||
int writingColor = currentConsole->fg;
|
||||
int screenColor = currentConsole->bg;
|
||||
@ -657,25 +668,37 @@ void consoleDrawChar(int c) {
|
||||
u32 bg = colorTable[screenColor];
|
||||
u32 fg = colorTable[writingColor];
|
||||
|
||||
u64 bval = *((u64*)fontdata);
|
||||
u128 *tmp = (u128*)fontdata;
|
||||
|
||||
if (currentConsole->flags & CONSOLE_UNDERLINE) bval |= 0xffUL << 7*8;
|
||||
u128 bvaltop = tmp[0];
|
||||
u128 bvalbtm = tmp[1];
|
||||
|
||||
if (currentConsole->flags & CONSOLE_CROSSED_OUT) bval |= 0xff << 3*8;
|
||||
if (currentConsole->flags & CONSOLE_UNDERLINE) bvalbtm |= (u128)0xffffULL << 7*16;
|
||||
|
||||
u8 mask = 0x80;
|
||||
if (currentConsole->flags & CONSOLE_CROSSED_OUT) bvaltop |= (u128)0xffffULL << 7*16;
|
||||
|
||||
u16 mask = 0x8000;
|
||||
|
||||
int i, j;
|
||||
|
||||
int x = (currentConsole->cursorX + currentConsole->windowX) * 8;
|
||||
int y = ((currentConsole->cursorY + currentConsole->windowY) *8 );
|
||||
int x = (currentConsole->cursorX + currentConsole->windowX) * 16;
|
||||
int y = ((currentConsole->cursorY + currentConsole->windowY) *16 );
|
||||
|
||||
u32 *screen;
|
||||
|
||||
for (i=0;i<8;i++) {
|
||||
for (i=0;i<16;i++) {
|
||||
for (j=0;j<8;j++) {
|
||||
screen = ¤tConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + j)];
|
||||
if (bval >> (8*j) & mask) { *screen = fg; }else{ *screen = bg; }
|
||||
uint32_t screenOffset = gfxGetFramebufferDisplayOffset(x + i, y + j);
|
||||
screen = ¤tConsole->frameBuffer[screenOffset];
|
||||
if (bvaltop >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; }
|
||||
screen = ¤tConsole->frameBuffer2[screenOffset];
|
||||
if (bvaltop >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; }
|
||||
|
||||
screenOffset = gfxGetFramebufferDisplayOffset(x + i, y + j + 8);
|
||||
screen = ¤tConsole->frameBuffer[screenOffset];
|
||||
if (bvalbtm >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; }
|
||||
screen = ¤tConsole->frameBuffer2[screenOffset];
|
||||
if (bvalbtm >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; }
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
@ -730,6 +753,8 @@ void consolePrintChar(int c) {
|
||||
case 13:
|
||||
currentConsole->cursorX = 0;
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
gfxWaitForVsync();
|
||||
break;
|
||||
default:
|
||||
consoleDrawChar(c);
|
||||
|
@ -469,6 +469,13 @@ Result fsdevExit(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
FsFileSystem* fsdevGetDefaultFileSystem(void)
|
||||
{
|
||||
if(fsdev_fsdevice_default==-1) return NULL;
|
||||
|
||||
return &fsdev_fsdevices[fsdev_fsdevice_default].fs;
|
||||
}
|
||||
|
||||
/*! Open a file
|
||||
*
|
||||
* @param[in,out] r newlib reentrancy struct
|
||||
|
@ -9,14 +9,17 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "runtime/devices/romfs_dev.h"
|
||||
#include "runtime/devices/fs_dev.h"
|
||||
#include "runtime/util/utf.h"
|
||||
#include "services/fs.h"
|
||||
|
||||
/// WARNING: This is not ready to be used.
|
||||
#include "runtime/env.h"
|
||||
#include "nro.h"
|
||||
|
||||
typedef struct romfs_mount
|
||||
{
|
||||
bool fd_type;
|
||||
FsFile fd;
|
||||
FsStorage fd_storage;
|
||||
time_t mtime;
|
||||
u64 offset;
|
||||
romfs_header header;
|
||||
@ -30,7 +33,6 @@ extern int __system_argc;
|
||||
extern char** __system_argv;
|
||||
|
||||
static char __component[PATH_MAX+1];
|
||||
//static uint16_t __utf16path[PATH_MAX+1];
|
||||
|
||||
#define romFS_root(m) ((romfs_dir*)(m)->dirTable)
|
||||
#define romFS_dir(m,x) ((romfs_dir*) ((u8*)(m)->dirTable + (x)))
|
||||
@ -39,16 +41,25 @@ static char __component[PATH_MAX+1];
|
||||
#define romFS_dir_mode (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH)
|
||||
#define romFS_file_mode (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH)
|
||||
|
||||
static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u32 size)
|
||||
static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u64 size)
|
||||
{
|
||||
u64 pos = mount->offset + offset;
|
||||
size_t read = 0;
|
||||
Result rc = fsFileRead(&mount->fd, pos, buffer, size, &read);
|
||||
Result rc = 0;
|
||||
if(!mount->fd_type)
|
||||
{
|
||||
rc = fsFileRead(&mount->fd, pos, buffer, size, &read);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = fsStorageRead(&mount->fd_storage, pos, buffer, size);
|
||||
read = size;
|
||||
}
|
||||
if (R_FAILED(rc)) return -1;
|
||||
return read;
|
||||
}
|
||||
|
||||
static bool _romfs_read_chk(romfs_mount *mount, u64 offset, void* buffer, u32 size)
|
||||
static bool _romfs_read_chk(romfs_mount *mount, u64 offset, void* buffer, u64 size)
|
||||
{
|
||||
return _romfs_read(mount, offset, buffer, size) == size;
|
||||
}
|
||||
@ -104,26 +115,8 @@ static devoptab_t romFS_devoptab =
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// File header
|
||||
/*#define _3DSX_MAGIC 0x58534433 // '3DSX'
|
||||
typedef struct
|
||||
{
|
||||
u32 magic;
|
||||
u16 headerSize, relocHdrSize;
|
||||
u32 formatVer;
|
||||
u32 flags;
|
||||
|
||||
// Sizes of the code, rodata and data segments +
|
||||
// size of the BSS section (uninitialized latter half of the data segment)
|
||||
u32 codeSegSize, rodataSegSize, dataSegSize, bssSize;
|
||||
// offset and size of smdh
|
||||
u32 smdhOffset, smdhSize;
|
||||
// offset to filesystem
|
||||
u32 fsOffset;
|
||||
} _3DSX_Header;*/
|
||||
|
||||
static Result romfsMountCommon(romfs_mount *mount);
|
||||
//static void romfsInitMtime(romfs_mount *mount, FS_ArchiveID archId, FS_Path archPath, FS_Path filePath);
|
||||
static void romfsInitMtime(romfs_mount *mount);
|
||||
|
||||
__attribute__((weak)) const char* __romfs_path = NULL;
|
||||
|
||||
@ -173,9 +166,19 @@ Result romfsMount(struct romfs_mount **p)
|
||||
if(mount == NULL)
|
||||
return 99;
|
||||
|
||||
if (/*envIsHomebrew()*/1)//TODO: How to handle?
|
||||
if (!envIsNso())
|
||||
{
|
||||
// RomFS appended to a 3DSX file
|
||||
// RomFS embedded in a NRO
|
||||
|
||||
mount->fd_type = 0;
|
||||
|
||||
FsFileSystem *sdfs = fsdevGetDefaultFileSystem();
|
||||
if(sdfs==NULL)
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* filename = __romfs_path;
|
||||
if (__system_argc > 0 && __system_argv[0])
|
||||
filename = __system_argv[0];
|
||||
@ -187,69 +190,57 @@ Result romfsMount(struct romfs_mount **p)
|
||||
|
||||
if (strncmp(filename, "sdmc:/", 6) == 0)
|
||||
filename += 5;
|
||||
/*else if (strncmp(filename, "3dslink:/", 9) == 0)
|
||||
else if (strncmp(filename, "nxlink:/", 8) == 0)
|
||||
{
|
||||
strncpy(__component, "/3ds", PATH_MAX);
|
||||
strncat(__component, filename+8, PATH_MAX);
|
||||
strncpy(__component, "/switch", PATH_MAX);
|
||||
strncat(__component, filename+7, PATH_MAX);
|
||||
__component[PATH_MAX] = 0;
|
||||
filename = __component;
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 2;
|
||||
}
|
||||
|
||||
//TODO
|
||||
/*ssize_t units = utf8_to_utf16(__utf16path, (const uint8_t*)filename, PATH_MAX);
|
||||
if (units < 0)
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 3;
|
||||
}
|
||||
if (units >= PATH_MAX)
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 4;
|
||||
}
|
||||
__utf16path[units] = 0;
|
||||
|
||||
FS_Path archPath = { PATH_EMPTY, 1, (u8*)"" };
|
||||
FS_Path filePath = { PATH_UTF16, (units+1)*2, (u8*)__utf16path };
|
||||
|
||||
Result rc = FSUSER_OpenFileDirectly(&mount->fd, ARCHIVE_SDMC, archPath, filePath, FS_OPEN_READ, 0);
|
||||
Result rc = fsFsOpenFile(sdfs, filename, FS_OPEN_READ, &mount->fd);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
romfs_free(mount);
|
||||
return rc;
|
||||
}
|
||||
|
||||
//romfsInitMtime(mount, ARCHIVE_SDMC, archPath, filePath);
|
||||
romfsInitMtime(mount);
|
||||
|
||||
_3DSX_Header hdr;
|
||||
if (!_romfs_read_chk(mount, 0, &hdr, sizeof(hdr))) goto _fail0;
|
||||
if (hdr.magic != _3DSX_MAGIC) goto _fail0;
|
||||
if (hdr.headerSize < sizeof(hdr)) goto _fail0;
|
||||
mount->offset = hdr.fsOffset;
|
||||
if (!mount->offset) goto _fail0;*/
|
||||
NroHeader hdr;
|
||||
NroAssetHeader asset_header;
|
||||
|
||||
if (!_romfs_read_chk(mount, sizeof(NroStart), &hdr, sizeof(hdr))) goto _fail0;
|
||||
if (hdr.magic != NROHEADER_MAGIC) goto _fail0;
|
||||
if (!_romfs_read_chk(mount, hdr.size, &asset_header, sizeof(asset_header))) goto _fail0;
|
||||
|
||||
if (asset_header.magic != NROASSETHEADER_MAGIC
|
||||
|| asset_header.version > NROASSETHEADER_VERSION
|
||||
|| asset_header.romfs.offset == 0
|
||||
|| asset_header.romfs.size == 0)
|
||||
goto _fail0;
|
||||
|
||||
mount->offset = hdr.size + asset_header.romfs.offset;
|
||||
}
|
||||
else//TODO
|
||||
else
|
||||
{
|
||||
// Regular RomFS
|
||||
/*u8 zeros[0xC];
|
||||
memset(zeros, 0, sizeof(zeros));
|
||||
|
||||
FS_Path archPath = { PATH_EMPTY, 1, (u8*)"" };
|
||||
FS_Path filePath = { PATH_BINARY, sizeof(zeros), zeros };
|
||||
mount->fd_type = 1;
|
||||
|
||||
Result rc = FSUSER_OpenFileDirectly(&mount->fd, ARCHIVE_ROMFS, archPath, filePath, FS_OPEN_READ, 0);
|
||||
Result rc = fsOpenDataStorageByCurrentProcess(&mount->fd_storage);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
romfs_free(mount);
|
||||
return rc;
|
||||
}
|
||||
|
||||
//romfsInitMtime(mount, ARCHIVE_ROMFS, archPath, filePath);*/
|
||||
romfsInitMtime(mount);
|
||||
}
|
||||
|
||||
Result ret = romfsMountCommon(mount);
|
||||
@ -258,8 +249,9 @@ Result romfsMount(struct romfs_mount **p)
|
||||
|
||||
return ret;
|
||||
|
||||
//_fail0:
|
||||
fsFileClose(&mount->fd);
|
||||
_fail0:
|
||||
if(!mount->fd_type)fsFileClose(&mount->fd);
|
||||
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
|
||||
romfs_free(mount);
|
||||
return 10;
|
||||
}
|
||||
@ -270,6 +262,7 @@ Result romfsMountFromFile(FsFile file, u64 offset, struct romfs_mount **p)
|
||||
if(mount == NULL)
|
||||
return 99;
|
||||
|
||||
mount->fd_type = 0;
|
||||
mount->fd = file;
|
||||
mount->offset = offset;
|
||||
|
||||
@ -280,6 +273,23 @@ Result romfsMountFromFile(FsFile file, u64 offset, struct romfs_mount **p)
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result romfsMountFromStorage(FsStorage storage, u64 offset, struct romfs_mount **p)
|
||||
{
|
||||
romfs_mount *mount = romfs_alloc();
|
||||
if(mount == NULL)
|
||||
return 99;
|
||||
|
||||
mount->fd_type = 1;
|
||||
mount->fd_storage = storage;
|
||||
mount->offset = offset;
|
||||
|
||||
Result ret = romfsMountCommon(mount);
|
||||
if(R_SUCCEEDED(ret) && p)
|
||||
*p = mount;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result romfsMountCommon(romfs_mount *mount)
|
||||
{
|
||||
if (_romfs_read(mount, 0, &mount->header, sizeof(mount->header)) != sizeof(mount->header))
|
||||
@ -318,35 +328,16 @@ Result romfsMountCommon(romfs_mount *mount)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
fsFileClose(&mount->fd);
|
||||
if(!mount->fd_type)fsFileClose(&mount->fd);
|
||||
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
|
||||
romfs_free(mount);
|
||||
return 10;
|
||||
}
|
||||
|
||||
/*static void romfsInitMtime(romfs_mount *mount, FS_ArchiveID archId, FS_Path archPath, FS_Path filePath)
|
||||
static void romfsInitMtime(romfs_mount *mount)
|
||||
{
|
||||
u64 mtime;
|
||||
FS_Archive arch;
|
||||
Result rc;
|
||||
|
||||
mount->mtime = time(NULL);
|
||||
rc = FSUSER_OpenArchive(&arch, archId, archPath);
|
||||
if (R_FAILED(rc))
|
||||
return;
|
||||
|
||||
rc = FSUSER_ControlArchive(arch, ARCHIVE_ACTION_GET_TIMESTAMP,
|
||||
(void*)filePath.data, filePath.size,
|
||||
&mtime, sizeof(mtime));
|
||||
FSUSER_CloseArchive(arch);
|
||||
if (R_FAILED(rc))
|
||||
return;*/
|
||||
|
||||
/* convert from milliseconds to seconds */
|
||||
//mtime /= 1000;
|
||||
/* convert from 2000-based timestamp to UNIX timestamp */
|
||||
/*mtime += 946684800;
|
||||
mount->mtime = mtime;
|
||||
}*/
|
||||
}
|
||||
|
||||
Result romfsBind(struct romfs_mount *mount)
|
||||
{
|
||||
@ -368,7 +359,8 @@ Result romfsUnmount(struct romfs_mount *mount)
|
||||
if(mount)
|
||||
{
|
||||
// unmount specific
|
||||
fsFileClose(&mount->fd);
|
||||
if(!mount->fd_type)fsFileClose(&mount->fd);
|
||||
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
|
||||
romfs_free(mount);
|
||||
}
|
||||
else
|
||||
@ -376,7 +368,8 @@ Result romfsUnmount(struct romfs_mount *mount)
|
||||
// unmount everything
|
||||
while(romfs_mount_list)
|
||||
{
|
||||
fsFileClose(&romfs_mount_list->fd);
|
||||
if(!romfs_mount_list->fd_type)fsFileClose(&romfs_mount_list->fd);
|
||||
if(romfs_mount_list->fd_type)fsStorageClose(&romfs_mount_list->fd_storage);
|
||||
romfs_free(romfs_mount_list);
|
||||
}
|
||||
}
|
||||
@ -483,7 +476,7 @@ static int navigateToDir(romfs_mount *mount, romfs_dir** ppDir, const char** pPa
|
||||
}
|
||||
}
|
||||
|
||||
*ppDir = searchForDir(mount, *ppDir, (uint8_t*)component, strlen(component)+1);
|
||||
*ppDir = searchForDir(mount, *ppDir, (uint8_t*)component, strlen(component));
|
||||
if (!*ppDir)
|
||||
return EEXIST;
|
||||
}
|
||||
@ -551,7 +544,7 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
|
||||
if (r->_errno != 0)
|
||||
return -1;
|
||||
|
||||
romfs_file* file = searchForFile(fileobj->mount, curDir, (uint8_t*)path, strlen(path)+1);
|
||||
romfs_file* file = searchForFile(fileobj->mount, curDir, (uint8_t*)path, strlen(path));
|
||||
if (!file)
|
||||
{
|
||||
if(flags & O_CREAT)
|
||||
@ -567,7 +560,7 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
|
||||
}
|
||||
|
||||
fileobj->file = file;
|
||||
fileobj->offset = (u64)fileobj->mount->header.fileDataOff + file->dataOff;
|
||||
fileobj->offset = fileobj->mount->header.fileDataOff + file->dataOff;
|
||||
fileobj->pos = 0;
|
||||
|
||||
return 0;
|
||||
@ -669,7 +662,7 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
|
||||
if(r->_errno != 0)
|
||||
return -1;
|
||||
|
||||
romfs_dir* dir = searchForDir(mount, curDir, (uint8_t*)path, strlen(path)+1);
|
||||
romfs_dir* dir = searchForDir(mount, curDir, (uint8_t*)path, strlen(path));
|
||||
if(dir)
|
||||
{
|
||||
memset(st, 0, sizeof(*st));
|
||||
@ -684,7 +677,7 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
|
||||
return 0;
|
||||
}
|
||||
|
||||
romfs_file* file = searchForFile(mount, curDir, (uint8_t*)path, strlen(path)+1);
|
||||
romfs_file* file = searchForFile(mount, curDir, (uint8_t*)path, strlen(path));
|
||||
if(file)
|
||||
{
|
||||
memset(st, 0, sizeof(*st));
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "services/fatal.h"
|
||||
#include "services/fs.h"
|
||||
#include "services/hid.h"
|
||||
#include "services/time.h"
|
||||
#include "services/applet.h"
|
||||
#include "runtime/devices/fs_dev.h"
|
||||
|
||||
@ -101,6 +102,10 @@ void __attribute__((weak)) __appInit(void)
|
||||
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_HID));
|
||||
}
|
||||
|
||||
rc = timeInitialize();
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_Time));
|
||||
|
||||
rc = fsInitialize();
|
||||
if (R_FAILED(rc))
|
||||
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS));
|
||||
@ -113,6 +118,7 @@ void __attribute__((weak)) __appExit(void)
|
||||
// Cleanup default services.
|
||||
fsdevExit();
|
||||
fsExit();
|
||||
timeExit();
|
||||
hidExit();
|
||||
appletExit();
|
||||
smExit();
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/iosupport.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/lock.h>
|
||||
@ -8,6 +9,7 @@
|
||||
#include "runtime/env.h"
|
||||
#include "kernel/mutex.h"
|
||||
#include "services/fatal.h"
|
||||
#include "services/time.h"
|
||||
#include "result.h"
|
||||
|
||||
void __attribute__((weak)) NORETURN __libnx_exit(int rc);
|
||||
@ -16,6 +18,9 @@ extern const u8 __tdata_lma[];
|
||||
extern const u8 __tdata_lma_end[];
|
||||
extern u8 __tls_start[];
|
||||
|
||||
/// TimeType passed to timeGetCurrentTime() by __libnx_gtod().
|
||||
__attribute__((weak)) TimeType __nx_time_type = TimeType_Default;
|
||||
|
||||
static struct _reent* __libnx_get_reent(void) {
|
||||
ThreadVars* tv = getThreadVars();
|
||||
if (tv->magic != THREADVARS_MAGIC)
|
||||
@ -23,9 +28,41 @@ static struct _reent* __libnx_get_reent(void) {
|
||||
return tv->reent;
|
||||
}
|
||||
|
||||
//TODO: timeGetCurrentTime() returns UTC time. How to handle timezones?
|
||||
|
||||
int __libnx_gtod(struct _reent *ptr, struct timeval *tp, struct timezone *tz) {
|
||||
if (tp != NULL) {
|
||||
u64 now=0;
|
||||
Result rc=0;
|
||||
|
||||
rc = timeGetCurrentTime(__nx_time_type, &now);
|
||||
if (R_FAILED(rc)) {
|
||||
ptr->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tp->tv_sec = now;
|
||||
tp->tv_usec = now*1000000;//timeGetCurrentTime() only returns seconds.
|
||||
}
|
||||
|
||||
if (tz != NULL) {
|
||||
tz->tz_minuteswest = 0;
|
||||
tz->tz_dsttime = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usleep(useconds_t useconds)
|
||||
{
|
||||
svcSleepThread(useconds * 1000ull);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void newlibSetup(void) {
|
||||
// Register newlib syscalls
|
||||
__syscalls.exit = __libnx_exit;
|
||||
__syscalls.gettod_r = __libnx_gtod;
|
||||
__syscalls.getreent = __libnx_get_reent;
|
||||
|
||||
// Register locking syscalls
|
||||
|
@ -503,6 +503,45 @@ Result appletGetAppletResourceUserId(u64 *out) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result appletGetDesiredLanguage(u64 *LanguageCode) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
if (!serviceIsActive(&g_appletSrv) || __nx_applet_type!=AppletType_Application)
|
||||
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 = 21;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_appletIFunctions);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void appletNotifyRunning(u8 *out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
@ -131,6 +131,41 @@ Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result fsOpenDataStorageByCurrentProcess(FsStorage* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 200;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_fsSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
out->h = r.Handles[0];
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Wrapper(s) for fsMountSaveData.
|
||||
Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID) {
|
||||
FsSave save;
|
||||
@ -595,7 +630,7 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
|
||||
}
|
||||
|
||||
void fsFsClose(FsFileSystem* fs) {
|
||||
svcCloseHandle(fs->h);
|
||||
if(fs->h != INVALID_HANDLE) svcCloseHandle(fs->h);
|
||||
}
|
||||
|
||||
// IFile implementation
|
||||
@ -778,12 +813,12 @@ Result fsFileGetSize(FsFile* f, u64* out) {
|
||||
}
|
||||
|
||||
void fsFileClose(FsFile* f) {
|
||||
svcCloseHandle(f->h);
|
||||
if(f->h != INVALID_HANDLE) svcCloseHandle(f->h);
|
||||
}
|
||||
|
||||
// IDirectory implementation
|
||||
void fsDirClose(FsDir* d) {
|
||||
svcCloseHandle(d->h);
|
||||
if(d->h != INVALID_HANDLE) svcCloseHandle(d->h);
|
||||
}
|
||||
|
||||
Result fsDirRead(FsDir* d, u64 inval, size_t* total_entries, size_t max_entries, FsDirectoryEntry *buf) {
|
||||
@ -858,3 +893,44 @@ Result fsDirGetEntryCount(FsDir* d, u64* count) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// IStorage implementation
|
||||
Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvBuffer(&c, buf, len, 1);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 offset;
|
||||
u64 read_size;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->offset = off;
|
||||
raw->read_size = len;
|
||||
|
||||
Result rc = ipcDispatch(s->h);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void fsStorageClose(FsStorage* s) {
|
||||
if(s->h != INVALID_HANDLE) svcCloseHandle(s->h);
|
||||
}
|
||||
|
||||
|
@ -267,6 +267,12 @@ u64 hidMouseButtonsUp(void) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void hidMouseRead(MousePosition *pos) {
|
||||
rwlockReadLock(&g_hidLock);
|
||||
*pos = g_mouseEntry.position;
|
||||
rwlockReadUnlock(&g_hidLock);
|
||||
}
|
||||
|
||||
bool hidKeyboardModifierHeld(HidKeyboardModifier modifier) {
|
||||
rwlockReadLock(&g_hidLock);
|
||||
bool tmp = g_keyboardModHeld & modifier;
|
||||
|
337
nx/source/services/set.c
Normal file
337
nx/source/services/set.c
Normal file
@ -0,0 +1,337 @@
|
||||
/**
|
||||
* @file set.h
|
||||
* @brief Settings services IPC wrapper.
|
||||
* @author plutoo
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "ipc.h"
|
||||
#include "kernel/detect.h"
|
||||
#include "services/set.h"
|
||||
#include "services/sm.h"
|
||||
#include "services/applet.h"
|
||||
|
||||
static Service g_setSrv;
|
||||
static Service g_setsysSrv;
|
||||
|
||||
static bool g_setLanguageCodesInitialized;
|
||||
static u64 g_setLanguageCodes[0x40];
|
||||
static s32 g_setLanguageCodesTotal;
|
||||
|
||||
static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode);
|
||||
|
||||
Result setInitialize(void)
|
||||
{
|
||||
if (serviceIsActive(&g_setSrv))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
|
||||
|
||||
g_setLanguageCodesInitialized = 0;
|
||||
|
||||
return smGetService(&g_setSrv, "set");
|
||||
}
|
||||
|
||||
void setExit(void)
|
||||
{
|
||||
serviceClose(&g_setSrv);
|
||||
}
|
||||
|
||||
Result setsysInitialize(void)
|
||||
{
|
||||
if (serviceIsActive(&g_setsysSrv))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
|
||||
|
||||
return smGetService(&g_setsysSrv, "set:sys");
|
||||
}
|
||||
|
||||
void setsysExit(void)
|
||||
{
|
||||
serviceClose(&g_setsysSrv);
|
||||
}
|
||||
|
||||
static Result setInitializeLanguageCodesCache(void) {
|
||||
if (g_setLanguageCodesInitialized) return 0;
|
||||
Result rc = 0;
|
||||
|
||||
rc = setGetAvailableLanguageCodes(&g_setLanguageCodesTotal, g_setLanguageCodes, sizeof(g_setLanguageCodes)/sizeof(u64));
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
if (g_setLanguageCodesTotal < 0) g_setLanguageCodesTotal = 0;
|
||||
|
||||
g_setLanguageCodesInitialized = 1;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setMakeLanguage(u64 LanguageCode, s32 *Language) {
|
||||
Result rc = setInitializeLanguageCodesCache();
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
s32 i;
|
||||
rc = MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
for (i=0; i<g_setLanguageCodesTotal; i++) {
|
||||
if (g_setLanguageCodes[i] == LanguageCode) {
|
||||
*Language = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setMakeLanguageCode(s32 Language, u64 *LanguageCode) {
|
||||
Result rc = setInitializeLanguageCodesCache();
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
if (Language < 0)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
|
||||
if (Language >= g_setLanguageCodesTotal) {
|
||||
if (!kernelAbove400()) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
return _setMakeLanguageCode(Language, LanguageCode);
|
||||
}
|
||||
|
||||
*LanguageCode = g_setLanguageCodes[Language];
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setGetSystemLanguage(u64 *LanguageCode) {
|
||||
//This is disabled because the returned LanguageCode can differ from the system language, for example ja instead of {English}.
|
||||
/*Result rc = appletGetDesiredLanguage(LanguageCode);
|
||||
if (R_SUCCEEDED(rc)) return rc;*/
|
||||
|
||||
return setGetLanguageCode(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;
|
||||
}
|
||||
|
||||
Result setGetAvailableLanguageCodes(s32 *total_entries, u64 *LanguageCodes, size_t max_entries) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
Result rc=0;
|
||||
bool new_cmd = kernelAbove400();
|
||||
|
||||
if (!new_cmd) {//On system-version <4.0.0 the sysmodule will close the session if max_entries is too large.
|
||||
s32 tmptotal = 0;
|
||||
|
||||
rc = setGetAvailableLanguageCodeCount(&tmptotal);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = kernelAbove400() ? 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;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result setGetRegionCode(s32 *RegionCode) {
|
||||
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) && RegionCode) *RegionCode = resp->RegionCode;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
189
nx/source/services/time.c
Normal file
189
nx/source/services/time.c
Normal file
@ -0,0 +1,189 @@
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "ipc.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 Result _timeGetSession(Service* srv_out, u64 cmd_id);
|
||||
|
||||
Result timeInitialize(void)
|
||||
{
|
||||
if (serviceIsActive(&g_timeSrv))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
|
||||
|
||||
Result rc;
|
||||
|
||||
rc = smGetService(&g_timeSrv, "time:s");
|
||||
if (R_FAILED(rc))
|
||||
rc = smGetService(&g_timeSrv, "time:u");
|
||||
|
||||
if (R_FAILED(rc))
|
||||
return rc;
|
||||
|
||||
rc = _timeGetSession(&g_timeUserSystemClock, 0);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _timeGetSession(&g_timeNetworkSystemClock, 1);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _timeGetSession(&g_timeTimeZoneService, 3);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _timeGetSession(&g_timeLocalSystemClock, 4);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
timeExit();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void timeExit(void)
|
||||
{
|
||||
if (!serviceIsActive(&g_timeSrv))
|
||||
return;
|
||||
|
||||
serviceClose(&g_timeLocalSystemClock);
|
||||
serviceClose(&g_timeTimeZoneService);
|
||||
serviceClose(&g_timeNetworkSystemClock);
|
||||
serviceClose(&g_timeUserSystemClock);
|
||||
serviceClose(&g_timeSrv);
|
||||
}
|
||||
|
||||
Service* timeGetSessionService(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) {
|
||||
if (type==TimeType_UserSystemClock) {
|
||||
return &g_timeUserSystemClock;
|
||||
}
|
||||
else if (type==TimeType_NetworkSystemClock) {
|
||||
return &g_timeNetworkSystemClock;
|
||||
}
|
||||
else if (type==TimeType_LocalSystemClock) {
|
||||
return &g_timeLocalSystemClock;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Result timeGetCurrentTime(TimeType type, u64 *timestamp) {
|
||||
Service *srv = _timeGetClockSession(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;
|
||||
}
|
||||
|
||||
Result timeSetCurrentTime(TimeType type, u64 timestamp) {
|
||||
Service *srv = _timeGetClockSession(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;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ endif
|
||||
|
||||
include $(DEVKITPRO)/devkitA64/base_rules
|
||||
|
||||
PORTLIBS := $(PORTLIBS_PATH)/switch $(PORTLIBS_PATH)/armv8-a
|
||||
PORTLIBS := $(PORTLIBS_PATH)/switch
|
||||
|
||||
LIBNX ?= $(DEVKITPRO)/libnx
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user