Merge branch 'master' into gpu

This commit is contained in:
plutoo 2018-02-27 09:03:07 +01:00
commit 282a5ad904
29 changed files with 1081 additions and 146 deletions

View File

@ -22,5 +22,10 @@
## Functions
`modulenameFunctionName`
### Submodule function naming
Singletons use names like smInitialize/smExit
Objects use names like tmemCreate/tmemClose
## Macros
`LIKE_THIS`

View File

@ -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

View File

@ -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
}

View File

@ -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
View 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;

View File

@ -64,6 +64,7 @@ enum {
LibnxError_JitUnavailable,
LibnxError_WeirdKernel,
LibnxError_IncompatSysVer,
LibnxError_InitFail_Time,
};
/// libnx nvidia error codes

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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);

View 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);

View 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);

View File

@ -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];

View File

@ -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)

View File

@ -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 = &currentConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + j)];
from = &currentConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + 8 + j)];
from = &currentConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + 16 + j)];
*to = *from;
to = &currentConsole->frameBuffer2[gfxGetFramebufferDisplayOffset(x + i, y + j)];
from = &currentConsole->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 = &currentConsole->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 = &currentConsole->frameBuffer[screenOffset];
if (bvaltop >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; }
screen = &currentConsole->frameBuffer2[screenOffset];
if (bvaltop >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; }
screenOffset = gfxGetFramebufferDisplayOffset(x + i, y + j + 8);
screen = &currentConsole->frameBuffer[screenOffset];
if (bvalbtm >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; }
screen = &currentConsole->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);

View File

@ -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

View File

@ -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));

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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
View 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
View 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;
}

View File

@ -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