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 ## Functions
`modulenameFunctionName` `modulenameFunctionName`
### Submodule function naming
Singletons use names like smInitialize/smExit
Objects use names like tmemCreate/tmemClose
## Macros ## Macros
`LIKE_THIS` `LIKE_THIS`

View File

@ -5,7 +5,3 @@ Based on libctru.
# Install instructions # Install instructions
See [Switchbrew](http://switchbrew.org/index.php?title=Setting_up_Development_Environment). 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/types.h"
#include "switch/result.h" #include "switch/result.h"
#include "switch/nro.h"
#include "switch/kernel/svc.h" #include "switch/kernel/svc.h"
#include "switch/kernel/tmem.h" #include "switch/kernel/tmem.h"
#include "switch/kernel/shmem.h" #include "switch/kernel/shmem.h"
#include "switch/kernel/mutex.h" #include "switch/kernel/mutex.h"
#include "switch/kernel/rwlock.h" #include "switch/kernel/rwlock.h"
#include "switch/kernel/condvar.h"
#include "switch/kernel/thread.h" #include "switch/kernel/thread.h"
#include "switch/kernel/virtmem.h" #include "switch/kernel/virtmem.h"
#include "switch/kernel/detect.h" #include "switch/kernel/detect.h"
@ -35,12 +38,14 @@ extern "C" {
#include "switch/services/audout.h" #include "switch/services/audout.h"
#include "switch/services/bsd.h" #include "switch/services/bsd.h"
#include "switch/services/fatal.h" #include "switch/services/fatal.h"
#include "switch/services/time.h"
#include "switch/services/usb.h" #include "switch/services/usb.h"
#include "switch/services/hid.h" #include "switch/services/hid.h"
#include "switch/services/irs.h" #include "switch/services/irs.h"
#include "switch/services/vi.h" #include "switch/services/vi.h"
#include "switch/services/nv.h" #include "switch/services/nv.h"
#include "switch/services/pm.h" #include "switch/services/pm.h"
#include "switch/services/set.h"
#include "switch/display/gfx.h" #include "switch/display/gfx.h"
#include "switch/display/binder.h" #include "switch/display/binder.h"
@ -65,6 +70,7 @@ extern "C" {
#include "switch/runtime/devices/console.h" #include "switch/runtime/devices/console.h"
#include "switch/runtime/devices/usb_comms.h" #include "switch/runtime/devices/usb_comms.h"
#include "switch/runtime/devices/fs_dev.h" #include "switch/runtime/devices/fs_dev.h"
#include "switch/runtime/devices/romfs_dev.h"
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -14,7 +14,7 @@
/// Same as \ref RGBA8 except with alpha=0xff. /// Same as \ref RGBA8 except with alpha=0xff.
#define RGBA8_MAXALPHA(r,g,b) RGBA8(r,g,b,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 typedef enum
{ {
GfxMode_TiledSingle, ///< Single-buffering with raw tiled (block-linear) framebuffer. 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_LinearDouble ///< Double-buffering with linear framebuffer, which is transferred to the actual framebuffer by \ref gfxFlushBuffers().
} GfxMode; } GfxMode;
/// Framebuffer pixel-format is RGBA8888, there's no known way to change this.
/** /**
* @brief Initializes the graphics subsystem. * @brief Initializes the graphics subsystem.
* @warning Do not use \ref viInitialize when using this function. * @warning Do not use \ref viInitialize when using this function.
@ -83,6 +85,12 @@ size_t gfxGetFramebufferSize(void);
/// Sets the \ref GfxMode. /// Sets the \ref GfxMode.
void gfxSetMode(GfxMode mode); 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. /// 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); 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_aligned_width;
extern size_t g_gfx_framebuf_display_height; 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) //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 = ((y & 127) / 16) + (x/16*8) + ((y/16/8)*(g_gfx_framebuf_aligned_width/16*8));
tmp_pos *= 16*16 * 4; 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_JitUnavailable,
LibnxError_WeirdKernel, LibnxError_WeirdKernel,
LibnxError_IncompatSysVer, LibnxError_IncompatSysVer,
LibnxError_InitFail_Time,
}; };
/// libnx nvidia error codes /// libnx nvidia error codes

View File

@ -37,7 +37,7 @@ typedef bool(*ConsolePrint)(void* con, int c);
/// A font struct for the console. /// A font struct for the console.
typedef struct ConsoleFont 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 asciiOffset; ///< Offset to the first valid character in the font table
u16 numChars; ///< Number of characters in the font graphics u16 numChars; ///< Number of characters in the font graphics
}ConsoleFont; }ConsoleFont;
@ -51,18 +51,18 @@ typedef struct ConsoleFont
* { * {
* //Font: * //Font:
* { * {
* (u8*)default_font_bin, //font gfx * (u16*)default_font_bin, //font gfx
* 0, //first ascii character in the set * 0, //first ascii character in the set
* 128, //number of characters in the font set * 128, //number of characters in the font set
* }, * },
* 0,0, //cursorX cursorY * 0,0, //cursorX cursorY
* 0,0, //prevcursorX prevcursorY * 0,0, //prevcursorX prevcursorY
* 160, //console width * 80, //console width
* 90, //console height * 45, //console height
* 0, //window x * 0, //window x
* 0, //window y * 0, //window y
* 160, //window width * 80, //window width
* 90, //window height * 45, //window height
* 3, //tab size * 3, //tab size
* 0, //font character offset * 0, //font character offset
* 0, //print callback * 0, //print callback
@ -75,6 +75,7 @@ typedef struct PrintConsole
ConsoleFont font; ///< Font of the console ConsoleFont font; ///< Font of the console
u32 *frameBuffer; ///< Framebuffer address u32 *frameBuffer; ///< Framebuffer address
u32 *frameBuffer2; ///< Framebuffer address
int cursorX; ///< Current X location of the cursor (as a tile offset by default) 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) 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). /// 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. /// This is not used automatically at device unmount.
Result fsdevCommitDevice(const char *name); 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. * @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 offset Offset of the RomFS within the file.
* @param mount Output mount handle * @param mount Output mount handle
*/ */
@ -76,6 +76,18 @@ static inline Result romfsInitFromFile(FsFile file, u64 offset)
return romfsMountFromFile(file, offset, NULL); 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 /// Bind the RomFS mount
Result romfsBind(struct romfs_mount *mount); Result romfsBind(struct romfs_mount *mount);

View File

@ -51,6 +51,8 @@ Result appletGetAppletResourceUserId(u64 *out);
void appletNotifyRunning(u8 *out); void appletNotifyRunning(u8 *out);
Result appletCreateManagedDisplayLayer(u64 *out); Result appletCreateManagedDisplayLayer(u64 *out);
Result appletGetDesiredLanguage(u64 *LanguageCode);
/** /**
* @brief Controls whether screenshot-capture is allowed. * @brief Controls whether screenshot-capture is allowed.
* @param val 0 = disable, 1 = enable. * @param val 0 = disable, 1 = enable.

View File

@ -1,6 +1,7 @@
/** /**
* @file fs.h * @file fs.h
* @brief Filesystem (fsp-srv) service IPC wrapper. * @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 plutoo
* @author yellows8 * @author yellows8
* @copyright libnx Authors * @copyright libnx Authors
@ -91,8 +92,11 @@ void fsExit(void);
Service* fsGetServiceSession(void); Service* fsGetServiceSession(void);
/// Do not call this directly, see fs_dev.h.
Result fsMountSdcard(FsFileSystem* out); Result fsMountSdcard(FsFileSystem* out);
Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save); Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save);
Result fsOpenDataStorageByCurrentProcess(FsStorage* out);
// todo: Rest of commands here // todo: Rest of commands here
/// FsFileSystem can be mounted with fs_dev for use with stdio, see fs_dev.h. /// 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); Result fsDirGetEntryCount(FsDir* d, u64* count);
void fsDirClose(FsDir* d); 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; s32 dy;
} JoystickPosition; } JoystickPosition;
typedef struct MousePosition
{
u32 x;
u32 y;
u32 velocityX;
u32 velocityY;
u32 scrollVelocityX;
u32 scrollVelocityY;
} MousePosition;
#define JOYSTICK_MAX (0x8000) #define JOYSTICK_MAX (0x8000)
#define JOYSTICK_MIN (-0x8000) #define JOYSTICK_MIN (-0x8000)
@ -399,12 +409,7 @@ typedef struct HidMouseEntry
{ {
u64 timestamp; u64 timestamp;
u64 timestamp_2; u64 timestamp_2;
u32 x; MousePosition position;
u32 y;
u32 velocityX;
u32 velocityY;
u32 scrollVelocityX;
u32 scrollVelocityY;
u64 buttons; u64 buttons;
} HidMouseEntry; } HidMouseEntry;
static_assert(sizeof(HidMouseEntry) == 0x30, "Hid mouse entry structure has incorrect size"); static_assert(sizeof(HidMouseEntry) == 0x30, "Hid mouse entry structure has incorrect size");
@ -552,6 +557,7 @@ u64 hidKeysUp(HidControllerID id);
u64 hidMouseButtonsHeld(void); u64 hidMouseButtonsHeld(void);
u64 hidMouseButtonsDown(void); u64 hidMouseButtonsDown(void);
u64 hidMouseButtonsUp(void); u64 hidMouseButtonsUp(void);
void hidMouseRead(MousePosition *pos);
bool hidKeyboardModifierHeld(HidKeyboardModifier modifier); bool hidKeyboardModifierHeld(HidKeyboardModifier modifier);
bool hidKeyboardModifierDown(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 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_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_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_framebuf_display_width=0, g_gfx_framebuf_display_height=0;
size_t g_gfx_singleframebuf_size=0; size_t g_gfx_singleframebuf_size=0;
size_t g_gfx_singleframebuf_linear_size=0; size_t g_gfx_singleframebuf_linear_size=0;
bool g_gfx_drawflip = true;
static AppletHookCookie g_gfx_autoresolution_applethookcookie; static AppletHookCookie g_gfx_autoresolution_applethookcookie;
static bool g_gfx_autoresolution_enabled; 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); //static Result _gfxGetDisplayResolution(u64 *width, u64 *height);
// TODO: Let the user configure some of this?
static BqQueueBufferInput g_gfxQueueBufferData = { static BqQueueBufferInput g_gfxQueueBufferData = {
.timestamp = 0x0, .timestamp = 0x0,
.isAutoTimestamp = 0x1, .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. 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. //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); 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_gfxFramebufSize = 0;
g_gfxMode = GfxMode_LinearDouble; 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_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested));
memset(&g_gfx_DequeueBuffer_fence, 0, sizeof(g_gfx_DequeueBuffer_fence)); memset(&g_gfx_DequeueBuffer_fence, 0, sizeof(g_gfx_DequeueBuffer_fence));
@ -538,6 +545,18 @@ void gfxSetMode(GfxMode mode) {
g_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) { void gfxFlushBuffers(void) {
u32 *actual_framebuf = (u32*)&g_gfxFramebuf[g_gfxCurrentBuffer*g_gfx_singleframebuf_size]; 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 condvarWaitTimeout(CondVar* c, u64 timeout) {
Result rc; 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. // On timeout, we need to acquire it manually.
if (rc == 0xEA01) if (rc == 0xEA01)

View File

@ -42,19 +42,20 @@ PrintConsole defaultConsole =
{ {
//Font: //Font:
{ {
(u8*)default_font_bin, //font gfx (u16*)default_font_bin, //font gfx
0, //first ascii character in the set 0, //first ascii character in the set
256 //number of characters in the font set 256 //number of characters in the font set
}, },
(u32*)NULL, (u32*)NULL,
(u32*)NULL,
0,0, //cursorX cursorY 0,0, //cursorX cursorY
0,0, //prevcursorX prevcursorY 0,0, //prevcursorX prevcursorY
160, //console width 80, //console width
90, //console height 45, //console height
0, //window x 0, //window x
0, //window y 0, //window y
160, //window width 80, //window width
90, //window height 45, //window height
3, //tab size 3, //tab size
7, // foreground color 7, // foreground color
0, // background color 0, // background color
@ -123,6 +124,8 @@ static void consoleCls(char mode) {
} }
} }
gfxFlushBuffers(); gfxFlushBuffers();
gfxSwapBuffers();
gfxWaitForVsync();
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
static void consoleClearLine(char mode) { static void consoleClearLine(char mode) {
@ -176,6 +179,8 @@ static void consoleClearLine(char mode) {
} }
} }
gfxFlushBuffers(); gfxFlushBuffers();
gfxSwapBuffers();
gfxWaitForVsync();
} }
@ -547,13 +552,16 @@ PrintConsole* consoleInit(PrintConsole* console) {
console->consoleInitialised = 1; console->consoleInitialised = 1;
gfxSetMode(GfxMode_TiledSingle); gfxSetMode(GfxMode_TiledDouble);
console->frameBuffer = (u32*)gfxGetFramebuffer(NULL, NULL);
gfxSwapBuffers();
console->frameBuffer2 = (u32*)gfxGetFramebuffer(NULL, NULL);
gfxFlushBuffers(); gfxFlushBuffers();
gfxSwapBuffers();
gfxWaitForVsync(); gfxWaitForVsync();
console->frameBuffer = (u32*)gfxGetFramebuffer(NULL, NULL);
consoleCls('2'); consoleCls('2');
return currentConsole; return currentConsole;
@ -615,15 +623,18 @@ static void newRow(void) {
int i,j; int i,j;
u32 x, y; u32 x, y;
x = currentConsole->windowX * 8; x = currentConsole->windowX * 16;
y = currentConsole->windowY * 8; y = currentConsole->windowY * 16;
for (i=0; i<currentConsole->windowWidth*8; i++) { for (i=0; i<currentConsole->windowWidth*16; i++) {
u32 *from; u32 *from;
u32 *to; 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)]; 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; *to = *from;
} }
} }
@ -637,7 +648,7 @@ void consoleDrawChar(int c) {
c -= currentConsole->font.asciiOffset; c -= currentConsole->font.asciiOffset;
if ( c < 0 || c > currentConsole->font.numChars ) return; 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 writingColor = currentConsole->fg;
int screenColor = currentConsole->bg; int screenColor = currentConsole->bg;
@ -657,25 +668,37 @@ void consoleDrawChar(int c) {
u32 bg = colorTable[screenColor]; u32 bg = colorTable[screenColor];
u32 fg = colorTable[writingColor]; 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 i, j;
int x = (currentConsole->cursorX + currentConsole->windowX) * 8; int x = (currentConsole->cursorX + currentConsole->windowX) * 16;
int y = ((currentConsole->cursorY + currentConsole->windowY) *8 ); int y = ((currentConsole->cursorY + currentConsole->windowY) *16 );
u32 *screen; u32 *screen;
for (i=0;i<8;i++) { for (i=0;i<16;i++) {
for (j=0;j<8;j++) { for (j=0;j<8;j++) {
screen = &currentConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + j)]; uint32_t screenOffset = gfxGetFramebufferDisplayOffset(x + i, y + j);
if (bval >> (8*j) & mask) { *screen = fg; }else{ *screen = bg; } 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; mask >>= 1;
} }
@ -730,6 +753,8 @@ void consolePrintChar(int c) {
case 13: case 13:
currentConsole->cursorX = 0; currentConsole->cursorX = 0;
gfxFlushBuffers(); gfxFlushBuffers();
gfxSwapBuffers();
gfxWaitForVsync();
break; break;
default: default:
consoleDrawChar(c); consoleDrawChar(c);

View File

@ -469,6 +469,13 @@ Result fsdevExit(void)
return 0; return 0;
} }
FsFileSystem* fsdevGetDefaultFileSystem(void)
{
if(fsdev_fsdevice_default==-1) return NULL;
return &fsdev_fsdevices[fsdev_fsdevice_default].fs;
}
/*! Open a file /*! Open a file
* *
* @param[in,out] r newlib reentrancy struct * @param[in,out] r newlib reentrancy struct

View File

@ -9,14 +9,17 @@
#include <unistd.h> #include <unistd.h>
#include "runtime/devices/romfs_dev.h" #include "runtime/devices/romfs_dev.h"
#include "runtime/devices/fs_dev.h"
#include "runtime/util/utf.h" #include "runtime/util/utf.h"
#include "services/fs.h" #include "services/fs.h"
#include "runtime/env.h"
/// WARNING: This is not ready to be used. #include "nro.h"
typedef struct romfs_mount typedef struct romfs_mount
{ {
bool fd_type;
FsFile fd; FsFile fd;
FsStorage fd_storage;
time_t mtime; time_t mtime;
u64 offset; u64 offset;
romfs_header header; romfs_header header;
@ -30,7 +33,6 @@ extern int __system_argc;
extern char** __system_argv; extern char** __system_argv;
static char __component[PATH_MAX+1]; static char __component[PATH_MAX+1];
//static uint16_t __utf16path[PATH_MAX+1];
#define romFS_root(m) ((romfs_dir*)(m)->dirTable) #define romFS_root(m) ((romfs_dir*)(m)->dirTable)
#define romFS_dir(m,x) ((romfs_dir*) ((u8*)(m)->dirTable + (x))) #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_dir_mode (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH)
#define romFS_file_mode (S_IFREG | 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; u64 pos = mount->offset + offset;
size_t read = 0; 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; if (R_FAILED(rc)) return -1;
return read; 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; 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 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; __attribute__((weak)) const char* __romfs_path = NULL;
@ -173,9 +166,19 @@ Result romfsMount(struct romfs_mount **p)
if(mount == NULL) if(mount == NULL)
return 99; 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; const char* filename = __romfs_path;
if (__system_argc > 0 && __system_argv[0]) if (__system_argc > 0 && __system_argv[0])
filename = __system_argv[0]; filename = __system_argv[0];
@ -187,69 +190,57 @@ Result romfsMount(struct romfs_mount **p)
if (strncmp(filename, "sdmc:/", 6) == 0) if (strncmp(filename, "sdmc:/", 6) == 0)
filename += 5; filename += 5;
/*else if (strncmp(filename, "3dslink:/", 9) == 0) else if (strncmp(filename, "nxlink:/", 8) == 0)
{ {
strncpy(__component, "/3ds", PATH_MAX); strncpy(__component, "/switch", PATH_MAX);
strncat(__component, filename+8, PATH_MAX); strncat(__component, filename+7, PATH_MAX);
__component[PATH_MAX] = 0; __component[PATH_MAX] = 0;
filename = __component; filename = __component;
}*/ }
else else
{ {
romfs_free(mount); romfs_free(mount);
return 2; return 2;
} }
//TODO Result rc = fsFsOpenFile(sdfs, filename, FS_OPEN_READ, &mount->fd);
/*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);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
romfs_free(mount); romfs_free(mount);
return rc; return rc;
} }
//romfsInitMtime(mount, ARCHIVE_SDMC, archPath, filePath); romfsInitMtime(mount);
_3DSX_Header hdr; NroHeader hdr;
if (!_romfs_read_chk(mount, 0, &hdr, sizeof(hdr))) goto _fail0; NroAssetHeader asset_header;
if (hdr.magic != _3DSX_MAGIC) goto _fail0;
if (hdr.headerSize < sizeof(hdr)) goto _fail0; if (!_romfs_read_chk(mount, sizeof(NroStart), &hdr, sizeof(hdr))) goto _fail0;
mount->offset = hdr.fsOffset; if (hdr.magic != NROHEADER_MAGIC) goto _fail0;
if (!mount->offset) 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 // Regular RomFS
/*u8 zeros[0xC];
memset(zeros, 0, sizeof(zeros));
FS_Path archPath = { PATH_EMPTY, 1, (u8*)"" }; mount->fd_type = 1;
FS_Path filePath = { PATH_BINARY, sizeof(zeros), zeros };
Result rc = FSUSER_OpenFileDirectly(&mount->fd, ARCHIVE_ROMFS, archPath, filePath, FS_OPEN_READ, 0); Result rc = fsOpenDataStorageByCurrentProcess(&mount->fd_storage);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
romfs_free(mount); romfs_free(mount);
return rc; return rc;
} }
//romfsInitMtime(mount, ARCHIVE_ROMFS, archPath, filePath);*/ romfsInitMtime(mount);
} }
Result ret = romfsMountCommon(mount); Result ret = romfsMountCommon(mount);
@ -258,8 +249,9 @@ Result romfsMount(struct romfs_mount **p)
return ret; return ret;
//_fail0: _fail0:
fsFileClose(&mount->fd); if(!mount->fd_type)fsFileClose(&mount->fd);
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
romfs_free(mount); romfs_free(mount);
return 10; return 10;
} }
@ -270,6 +262,7 @@ Result romfsMountFromFile(FsFile file, u64 offset, struct romfs_mount **p)
if(mount == NULL) if(mount == NULL)
return 99; return 99;
mount->fd_type = 0;
mount->fd = file; mount->fd = file;
mount->offset = offset; mount->offset = offset;
@ -280,6 +273,23 @@ Result romfsMountFromFile(FsFile file, u64 offset, struct romfs_mount **p)
return ret; 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) Result romfsMountCommon(romfs_mount *mount)
{ {
if (_romfs_read(mount, 0, &mount->header, sizeof(mount->header)) != sizeof(mount->header)) if (_romfs_read(mount, 0, &mount->header, sizeof(mount->header)) != sizeof(mount->header))
@ -318,35 +328,16 @@ Result romfsMountCommon(romfs_mount *mount)
return 0; return 0;
fail: fail:
fsFileClose(&mount->fd); if(!mount->fd_type)fsFileClose(&mount->fd);
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
romfs_free(mount); romfs_free(mount);
return 10; 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); 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) Result romfsBind(struct romfs_mount *mount)
{ {
@ -368,7 +359,8 @@ Result romfsUnmount(struct romfs_mount *mount)
if(mount) if(mount)
{ {
// unmount specific // unmount specific
fsFileClose(&mount->fd); if(!mount->fd_type)fsFileClose(&mount->fd);
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
romfs_free(mount); romfs_free(mount);
} }
else else
@ -376,7 +368,8 @@ Result romfsUnmount(struct romfs_mount *mount)
// unmount everything // unmount everything
while(romfs_mount_list) 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); 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) if (!*ppDir)
return EEXIST; return EEXIST;
} }
@ -551,7 +544,7 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
if (r->_errno != 0) if (r->_errno != 0)
return -1; 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 (!file)
{ {
if(flags & O_CREAT) 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->file = file;
fileobj->offset = (u64)fileobj->mount->header.fileDataOff + file->dataOff; fileobj->offset = fileobj->mount->header.fileDataOff + file->dataOff;
fileobj->pos = 0; fileobj->pos = 0;
return 0; return 0;
@ -669,7 +662,7 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
if(r->_errno != 0) if(r->_errno != 0)
return -1; 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) if(dir)
{ {
memset(st, 0, sizeof(*st)); memset(st, 0, sizeof(*st));
@ -684,7 +677,7 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
return 0; 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) if(file)
{ {
memset(st, 0, sizeof(*st)); memset(st, 0, sizeof(*st));

View File

@ -4,6 +4,7 @@
#include "services/fatal.h" #include "services/fatal.h"
#include "services/fs.h" #include "services/fs.h"
#include "services/hid.h" #include "services/hid.h"
#include "services/time.h"
#include "services/applet.h" #include "services/applet.h"
#include "runtime/devices/fs_dev.h" #include "runtime/devices/fs_dev.h"
@ -101,6 +102,10 @@ void __attribute__((weak)) __appInit(void)
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_HID)); fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_HID));
} }
rc = timeInitialize();
if (R_FAILED(rc))
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_Time));
rc = fsInitialize(); rc = fsInitialize();
if (R_FAILED(rc)) if (R_FAILED(rc))
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS)); fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS));
@ -113,6 +118,7 @@ void __attribute__((weak)) __appExit(void)
// Cleanup default services. // Cleanup default services.
fsdevExit(); fsdevExit();
fsExit(); fsExit();
timeExit();
hidExit(); hidExit();
appletExit(); appletExit();
smExit(); smExit();

View File

@ -1,4 +1,5 @@
#include <string.h> #include <string.h>
#include <errno.h>
#include <sys/iosupport.h> #include <sys/iosupport.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/lock.h> #include <sys/lock.h>
@ -8,6 +9,7 @@
#include "runtime/env.h" #include "runtime/env.h"
#include "kernel/mutex.h" #include "kernel/mutex.h"
#include "services/fatal.h" #include "services/fatal.h"
#include "services/time.h"
#include "result.h" #include "result.h"
void __attribute__((weak)) NORETURN __libnx_exit(int rc); void __attribute__((weak)) NORETURN __libnx_exit(int rc);
@ -16,6 +18,9 @@ extern const u8 __tdata_lma[];
extern const u8 __tdata_lma_end[]; extern const u8 __tdata_lma_end[];
extern u8 __tls_start[]; 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) { static struct _reent* __libnx_get_reent(void) {
ThreadVars* tv = getThreadVars(); ThreadVars* tv = getThreadVars();
if (tv->magic != THREADVARS_MAGIC) if (tv->magic != THREADVARS_MAGIC)
@ -23,9 +28,41 @@ static struct _reent* __libnx_get_reent(void) {
return tv->reent; 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) { void newlibSetup(void) {
// Register newlib syscalls // Register newlib syscalls
__syscalls.exit = __libnx_exit; __syscalls.exit = __libnx_exit;
__syscalls.gettod_r = __libnx_gtod;
__syscalls.getreent = __libnx_get_reent; __syscalls.getreent = __libnx_get_reent;
// Register locking syscalls // Register locking syscalls

View File

@ -503,6 +503,45 @@ Result appletGetAppletResourceUserId(u64 *out) {
return 0; 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) { void appletNotifyRunning(u8 *out) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);

View File

@ -131,6 +131,41 @@ Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save) {
return rc; 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. // Wrapper(s) for fsMountSaveData.
Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID) { Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID) {
FsSave save; FsSave save;
@ -595,7 +630,7 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
} }
void fsFsClose(FsFileSystem* fs) { void fsFsClose(FsFileSystem* fs) {
svcCloseHandle(fs->h); if(fs->h != INVALID_HANDLE) svcCloseHandle(fs->h);
} }
// IFile implementation // IFile implementation
@ -778,12 +813,12 @@ Result fsFileGetSize(FsFile* f, u64* out) {
} }
void fsFileClose(FsFile* f) { void fsFileClose(FsFile* f) {
svcCloseHandle(f->h); if(f->h != INVALID_HANDLE) svcCloseHandle(f->h);
} }
// IDirectory implementation // IDirectory implementation
void fsDirClose(FsDir* d) { 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) { 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; 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; return tmp;
} }
void hidMouseRead(MousePosition *pos) {
rwlockReadLock(&g_hidLock);
*pos = g_mouseEntry.position;
rwlockReadUnlock(&g_hidLock);
}
bool hidKeyboardModifierHeld(HidKeyboardModifier modifier) { bool hidKeyboardModifierHeld(HidKeyboardModifier modifier) {
rwlockReadLock(&g_hidLock); rwlockReadLock(&g_hidLock);
bool tmp = g_keyboardModHeld & modifier; 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 include $(DEVKITPRO)/devkitA64/base_rules
PORTLIBS := $(PORTLIBS_PATH)/switch $(PORTLIBS_PATH)/armv8-a PORTLIBS := $(PORTLIBS_PATH)/switch
LIBNX ?= $(DEVKITPRO)/libnx LIBNX ?= $(DEVKITPRO)/libnx