Merge remote-tracking branch 'origin/master' into gpu

This commit is contained in:
plutooo 2018-04-15 20:21:11 +02:00
commit 1e51ea6662
24 changed files with 1010 additions and 215 deletions

View File

@ -588,37 +588,37 @@ struct group_source_req {
* Unspecified * Unspecified
*/ */
#define IN6_IS_ADDR_UNSPECIFIED(a) \ #define IN6_IS_ADDR_UNSPECIFIED(a) \
((a)->__u6_addr.__u6_addr32[0] == 0 && \ ((a)->__u6_addr32[0] == 0 && \
(a)->__u6_addr.__u6_addr32[1] == 0 && \ (a)->__u6_addr32[1] == 0 && \
(a)->__u6_addr.__u6_addr32[2] == 0 && \ (a)->__u6_addr32[2] == 0 && \
(a)->__u6_addr.__u6_addr32[3] == 0) (a)->__u6_addr32[3] == 0)
/* /*
* Loopback * Loopback
*/ */
#define IN6_IS_ADDR_LOOPBACK(a) \ #define IN6_IS_ADDR_LOOPBACK(a) \
((a)->__u6_addr.__u6_addr32[0] == 0 && \ ((a)->__u6_addr32[0] == 0 && \
(a)->__u6_addr.__u6_addr32[1] == 0 && \ (a)->__u6_addr32[1] == 0 && \
(a)->__u6_addr.__u6_addr32[2] == 0 && \ (a)->__u6_addr32[2] == 0 && \
(a)->__u6_addr.__u6_addr32[3] == ntohl(1)) (a)->__u6_addr32[3] == ntohl(1))
/* /*
* IPv4 compatible * IPv4 compatible
*/ */
#define IN6_IS_ADDR_V4COMPAT(a) \ #define IN6_IS_ADDR_V4COMPAT(a) \
((a)->__u6_addr.__u6_addr32[0] == 0 && \ ((a)->__u6_addr32[0] == 0 && \
(a)->__u6_addr.__u6_addr32[1] == 0 && \ (a)->__u6_addr32[1] == 0 && \
(a)->__u6_addr.__u6_addr32[2] == 0 && \ (a)->__u6_addr32[2] == 0 && \
(a)->__u6_addr.__u6_addr32[3] != 0 && \ (a)->__u6_addr32[3] != 0 && \
(a)->__u6_addr.__u6_addr32[3] != ntohl(1)) (a)->__u6_addr32[3] != ntohl(1))
/* /*
* Mapped * Mapped
*/ */
#define IN6_IS_ADDR_V4MAPPED(a) \ #define IN6_IS_ADDR_V4MAPPED(a) \
((a)->__u6_addr.__u6_addr32[0] == 0 && \ ((a)->__u6_addr32[0] == 0 && \
(a)->__u6_addr.__u6_addr32[1] == 0 && \ (a)->__u6_addr32[1] == 0 && \
(a)->__u6_addr.__u6_addr32[2] == ntohl(0x0000ffff)) (a)->__u6_addr32[2] == ntohl(0x0000ffff))
#define __IPV6_ADDR_SCOPE_NODELOCAL 0x01 #define __IPV6_ADDR_SCOPE_NODELOCAL 0x01
#define __IPV6_ADDR_SCOPE_INTFACELOCAL 0x01 #define __IPV6_ADDR_SCOPE_INTFACELOCAL 0x01

View File

@ -78,6 +78,7 @@ extern "C" {
#include "switch/nvidia/cmds/3d_clear.h" #include "switch/nvidia/cmds/3d_clear.h"
#include "switch/runtime/env.h" #include "switch/runtime/env.h"
#include "switch/runtime/nxlink.h"
#include "switch/runtime/util/utf.h" #include "switch/runtime/util/utf.h"

View File

@ -13,5 +13,7 @@ bool kernelAbove200(void);
bool kernelAbove300(void); bool kernelAbove300(void);
/// Returns true if the kernel version is equal to or above 4.0.0. /// Returns true if the kernel version is equal to or above 4.0.0.
bool kernelAbove400(void); bool kernelAbove400(void);
/// Returns true if the kernel version is equal to or above 5.0.0.
bool kernelAbove500(void);
/// Returns true if the process has a debugger attached. /// Returns true if the process has a debugger attached.
bool detectDebugger(void); bool detectDebugger(void);

View File

@ -395,7 +395,7 @@ static inline Result ipcParse(IpcParsedCommand* r) {
r->Buffers[i] = (void*) (desc->Addr | ((packed >> 28) << 32) | (((packed >> 2) & 15) << 36)); r->Buffers[i] = (void*) (desc->Addr | ((packed >> 28) << 32) | (((packed >> 2) & 15) << 36));
r->BufferSizes[i] = desc->Size; r->BufferSizes[i] = desc->Size;
r->BufferTypes[i] = packed & 3; r->BufferTypes[i] = (BufferType) (packed & 3);
if (i < num_bufs_send) if (i < num_bufs_send)
r->BufferDirections[i] = BufferDirection_Send; r->BufferDirections[i] = BufferDirection_Send;

View File

@ -11,5 +11,21 @@
Result usbCommsInitialize(void); Result usbCommsInitialize(void);
void usbCommsExit(void); void usbCommsExit(void);
/// Same as usbCommsInitialize, except this can be used after usbCommsInitialize (or instead of usbCommsInitialize), for creating new interface(s).
/// bInterface* are the values for the same fields in usb.h \ref usb_interface_descriptor. \ref usbCommsInitialize uses USB_CLASS_VENDOR_SPEC for all of these internally.
Result usbCommsInitializeEx(u32 *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol);
/// Shutdown the specified interface. If no interfaces are remaining, this then uses \ref usbCommsExit internally.
void usbCommsExitEx(u32 interface);
/// Read data with the default interface.
size_t usbCommsRead(void* buffer, size_t size); size_t usbCommsRead(void* buffer, size_t size);
/// Write data with the default interface.
size_t usbCommsWrite(const void* buffer, size_t size); size_t usbCommsWrite(const void* buffer, size_t size);
/// Same as usbCommsRead except with the specified interface.
size_t usbCommsReadEx(void* buffer, size_t size, u32 interface);
/// Same as usbCommsWrite except with the specified interface.
size_t usbCommsWriteEx(const void* buffer, size_t size, u32 interface);

View File

@ -85,3 +85,6 @@ Result envSetNextLoad(const char* path, const char* argv);
/// Returns true if the environment supports envSetNextLoad. /// Returns true if the environment supports envSetNextLoad.
bool envHasNextLoad(void); bool envHasNextLoad(void);
/// Returns the Result from the last NRO.
Result envGetLastLoadResult(void);

View File

@ -0,0 +1,8 @@
#pragma once
struct in_addr;
extern struct in_addr __nxlink_host;
#define NXLINK_SERVER_PORT 28280
#define NXLINK_CLIENT_PORT 28771

View File

@ -8,9 +8,45 @@
#include "../types.h" #include "../types.h"
#include "sm.h" #include "sm.h"
typedef struct {
Service s;
} AccountProfile;
typedef struct
{
u32 unk_x0;
u32 iconID; ///< Icon ID. 0 = Mii, the rest are character icon IDs.
u8 iconBackgroundColorID; ///< Profile icon background color ID
u8 unk_x9[0x7];
u8 miiID[0x10]; ///< Some ID related to the Mii? All zeros when a character icon is used.
u8 unk_x20[0x60]; ///< Usually zeros?
} PACKED AccountUserData;
typedef struct
{
u128 userID;
u64 lastEditTimestamp; ///< POSIX UTC timestamp, for the last account edit.
char username[0x20]; ///< UTF-8 Username.
} PACKED AccountProfileBase;
Result accountInitialize(void); Result accountInitialize(void);
void accountExit(void); void accountExit(void);
Service* accountGetService(void); Service* accountGetService(void);
/// Get the userID for the currently active user. The output userID is only valid when the output account_selected==1, otherwise no user is currently selected. /// Get the userID for the currently active user. The output userID is only valid when the output account_selected==1, otherwise no user is currently selected.
/// An user is only selected when the user-account selection applet was used to select an user at least once before.
Result accountGetActiveUser(u128 *userID, bool *account_selected); Result accountGetActiveUser(u128 *userID, bool *account_selected);
/// Get an AccountProfile for the specified userID.
Result accountGetProfile(AccountProfile* out, u128 userID);
/// Get \ref AccountUserData and \ref AccountProfileBase for the specified profile, userdata is optional (can be NULL).
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase);
/// Get the icon image size.
Result accountProfileGetImageSize(AccountProfile* profile, size_t* image_size);
/// Load the JPEG profile icon, valid for both Miis and character icons. The output image_size is the same as the one from \ref accountProfileGetImageSize.
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, size_t* image_size);
void accountProfileClose(AccountProfile* profile);

View File

@ -1,7 +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. * 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, etc.
* @author plutoo * @author plutoo
* @author yellows8 * @author yellows8
* @copyright libnx Authors * @copyright libnx Authors
@ -14,31 +14,32 @@
#define FS_MAX_PATH 0x301 #define FS_MAX_PATH 0x301
/// For use with fsMountSaveData().
#define FS_MOUNTSAVEDATA_INVAL_DEFAULT 0x1
/// For use with FsSave. /// For use with FsSave.
#define FS_SAVEDATA_CURRENT_TITLEID 0 #define FS_SAVEDATA_CURRENT_TITLEID 0
/// For use with FsSave. /// For use with \ref FsSave and \ref FsSaveDataInfo.
#define FS_SAVEDATA_USERID_COMMONSAVE 0 #define FS_SAVEDATA_USERID_COMMONSAVE 0
typedef struct { typedef struct {
Handle h; Service s;
} FsFileSystem; } FsFileSystem;
typedef struct { typedef struct {
Handle h; Service s;
} FsFile; } FsFile;
typedef struct { typedef struct {
Handle h; Service s;
} FsDir; } FsDir;
typedef struct { typedef struct {
Handle h; Service s;
} FsStorage; } FsStorage;
typedef struct {
Service s;
} FsSaveDataIterator;
/// Directory entry. /// Directory entry.
typedef struct typedef struct
{ {
@ -55,12 +56,25 @@ typedef struct
u64 titleID; ///< titleID of the savedata to access when accessing other titles' savedata via SaveData, otherwise FS_SAVEDATA_CURRENT_TITLEID. u64 titleID; ///< titleID of the savedata to access when accessing other titles' savedata via SaveData, otherwise FS_SAVEDATA_CURRENT_TITLEID.
u128 userID; ///< userID of the user-specific savedata to access, otherwise FS_SAVEDATA_USERID_COMMONSAVE. See account.h. u128 userID; ///< userID of the user-specific savedata to access, otherwise FS_SAVEDATA_USERID_COMMONSAVE. See account.h.
u64 saveID; ///< saveID, 0 for SaveData. u64 saveID; ///< saveID, 0 for SaveData.
u64 ContentStorageId; ///< ContentStorageId? See FsContentStorageId. u64 SaveDataType; ///< See \ref FsSaveDataType.
u64 unk_x28; ///< 0 for SystemSaveData/SaveData. u64 unk_x28; ///< 0 for SystemSaveData/SaveData.
u64 unk_x30; ///< 0 for SystemSaveData/SaveData. u64 unk_x30; ///< 0 for SystemSaveData/SaveData.
u64 unk_x38; ///< 0 for SystemSaveData/SaveData. u64 unk_x38; ///< 0 for SystemSaveData/SaveData.
} PACKED FsSave; } PACKED FsSave;
typedef struct
{
u64 saveID_unk;
u8 SaveDataSpaceId; ///< See \ref FsSaveDataSpaceId.
u8 SaveDataType; ///< See \ref FsSaveDataType.
u8 pad[6];
u128 userID; ///< See userID for \ref FsSave.
u64 saveID; ///< See saveID for \ref FsSave.
u64 titleID; ///< titleID for FsSaveDataType_SaveData.
u64 size; ///< Raw saveimage size.
u8 unk_x38[0x28]; ///< Unknown. Usually zeros?
} PACKED FsSaveDataInfo;
typedef enum { typedef enum {
ENTRYTYPE_DIR = 0, ENTRYTYPE_DIR = 0,
ENTRYTYPE_FILE = 1 ENTRYTYPE_FILE = 1
@ -80,6 +94,16 @@ typedef enum
FS_DIROPEN_FILE = BIT(1), ///< Enable reading file entries. FS_DIROPEN_FILE = BIT(1), ///< Enable reading file entries.
} FsDirectoryFlags; } FsDirectoryFlags;
typedef enum
{
FsStorageId_None = 0,
FsStorageId_Host = 1,
FsStorageId_GameCard = 2,
FsStorageId_NandSystem = 3,
FsStorageId_NandUser = 4,
FsStorageId_SdCard = 5,
} FsStorageId;
typedef enum typedef enum
{ {
FS_CONTENTSTORAGEID_NandSystem = 0, FS_CONTENTSTORAGEID_NandSystem = 0,
@ -87,6 +111,26 @@ typedef enum
FS_CONTENTSTORAGEID_SdCard = 2, FS_CONTENTSTORAGEID_SdCard = 2,
} FsContentStorageId; } FsContentStorageId;
typedef enum
{
FsSaveDataSpaceId_NandSystem = 0,
FsSaveDataSpaceId_NandUser = 1,
FsSaveDataSpaceId_SdCard = 2,
FsSaveDataSpaceId_TemporaryStorage = 3,
FsSaveDataSpaceId_All = -1, ///< Pseudo value for fsOpenSaveDataIterator().
} FsSaveDataSpaceId;
typedef enum
{
FsSaveDataType_SystemSaveData = 0,
FsSaveDataType_SaveData = 1,
FsSaveDataType_BcatDeliveryCacheStorage = 2,
FsSaveDataType_DeviceSaveData = 3,
FsSaveDataType_TemporaryStorage = 4, ///< [3.0.0+]
FsSaveDataType_CacheStorage = 5, ///< [3.0.0+]
} FsSaveDataType;
Result fsInitialize(void); Result fsInitialize(void);
void fsExit(void); void fsExit(void);
@ -96,6 +140,8 @@ Service* fsGetServiceSession(void);
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 fsMountSystemSaveData(FsFileSystem* out, u8 inval, FsSave *save);
Result fsOpenSaveDataIterator(FsSaveDataIterator* out, s32 SaveDataSpaceId);
Result fsOpenDataStorageByCurrentProcess(FsStorage* out); Result fsOpenDataStorageByCurrentProcess(FsStorage* out);
// todo: Rest of commands here // todo: Rest of commands here
@ -105,6 +151,10 @@ Result fsOpenDataStorageByCurrentProcess(FsStorage* out);
/// See FsSave for titleID and userID. /// See FsSave for titleID and userID.
Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID); Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID);
/// Wrapper for fsMountSystemSaveData.
/// WARNING: You can brick when writing to SystemSaveData, if the data is corrupted etc.
Result fsMount_SystemSaveData(FsFileSystem* out, u64 saveID);
// IFileSystem // IFileSystem
Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags); Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags);
Result fsFsDeleteFile(FsFileSystem* fs, const char* path); Result fsFsDeleteFile(FsFileSystem* fs, const char* path);
@ -137,3 +187,9 @@ void fsDirClose(FsDir* d);
// IStorage // IStorage
Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len); Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len);
void fsStorageClose(FsStorage* s); void fsStorageClose(FsStorage* s);
// ISaveDataInfoReader
/// Read FsSaveDataInfo data into the buf array.
Result fsSaveDataIteratorRead(FsSaveDataIterator *s, FsSaveDataInfo* buf, size_t max_entries, size_t* total_entries);
void fsSaveDataIteratorClose(FsSaveDataIterator *s);

View File

@ -310,7 +310,7 @@ typedef enum
CONTROLLER_PLAYER_8 = 7, CONTROLLER_PLAYER_8 = 7,
CONTROLLER_HANDHELD = 8, CONTROLLER_HANDHELD = 8,
CONTROLLER_UNKNOWN = 9, CONTROLLER_UNKNOWN = 9,
CONTROLLER_P1_AUTO = 10, /// Not an actual HID-sysmodule ID. Only for hidKeys*(). Automatically uses CONTROLLER_PLAYER_1 when connected, otherwise uses CONTROLLER_HANDHELD. CONTROLLER_P1_AUTO = 10, /// Not an actual HID-sysmodule ID. Only for hidKeys*()/hidJoystickRead(). Automatically uses CONTROLLER_PLAYER_1 when connected, otherwise uses CONTROLLER_HANDHELD.
} HidControllerID; } HidControllerID;
typedef struct touchPosition typedef struct touchPosition
@ -581,17 +581,23 @@ void hidTouchRead(touchPosition *pos, u32 point_id);
void hidJoystickRead(JoystickPosition *pos, HidControllerID id, HidControllerJoystick stick); void hidJoystickRead(JoystickPosition *pos, HidControllerID id, HidControllerJoystick stick);
/// This can be used to check what CONTROLLER_P1_AUTO uses.
/// Returns 0 when CONTROLLER_PLAYER_1 is connected, otherwise returns 1 for handheld-mode.
bool hidGetHandheldMode(void);
/// Use this if you want to use a single joy-con as a dedicated CONTROLLER_PLAYER_*. /// Use this if you want to use a single joy-con as a dedicated CONTROLLER_PLAYER_*.
/// When used, both joy-cons in a pair should be used with this (CONTROLLER_PLAYER_1 and CONTROLLER_PLAYER_2 for example). /// When used, both joy-cons in a pair should be used with this (CONTROLLER_PLAYER_1 and CONTROLLER_PLAYER_2 for example).
/// id must be CONTROLLER_PLAYER_*. /// id must be CONTROLLER_PLAYER_*.
Result hidSetNpadJoyAssignmentModeSingleByDefault(HidControllerID id); Result hidSetNpadJoyAssignmentModeSingleByDefault(HidControllerID id);
/// Use this if you want to use a pair of joy-cons as a single CONTROLLER_PLAYER_*. Only necessary if you want to use this mode in your application after \ref hidSetNpadJoyAssignmentModeSingleByDefault was used with this pair of joy-cons.
/// Used automatically during app startup/exit for all controllers. /// Used automatically during app startup/exit for all controllers.
/// When used, both joy-cons in a pair should be used with this (CONTROLLER_PLAYER_1 and CONTROLLER_PLAYER_2 for example). /// When used, both joy-cons in a pair should be used with this (CONTROLLER_PLAYER_1 and CONTROLLER_PLAYER_2 for example).
/// id must be CONTROLLER_PLAYER_*. /// id must be CONTROLLER_PLAYER_*.
Result hidSetNpadJoyAssignmentModeDual(HidControllerID id); Result hidSetNpadJoyAssignmentModeDual(HidControllerID id);
Result hidInitializeVibrationDevices(u32 *VibrationDeviceHandles, size_t total_handles, HidControllerID id, HidControllerLayoutType type); Result hidInitializeVibrationDevices(u32 *VibrationDeviceHandles, size_t total_handles, HidControllerID id, HidControllerType type);
/// Send the VibrationValue to the specified VibrationDeviceHandle.
Result hidSendVibrationValue(u32 *VibrationDeviceHandle, HidVibrationValue *VibrationValue); Result hidSendVibrationValue(u32 *VibrationDeviceHandle, HidVibrationValue *VibrationValue);
/// Sets whether vibration is allowed, this also affects the config displayed by System Settings. /// Sets whether vibration is allowed, this also affects the config displayed by System Settings.
@ -599,3 +605,6 @@ Result hidPermitVibration(bool flag);
/// Gets whether vibration is allowed. /// Gets whether vibration is allowed.
Result hidIsVibrationPermitted(bool *flag); Result hidIsVibrationPermitted(bool *flag);
/// Send VibrationValues[index] to VibrationDeviceHandles[index], where count is the number of entries in the VibrationDeviceHandles/VibrationValues arrays.
Result hidSendVibrationValues(u32 *VibrationDeviceHandles, HidVibrationValue *VibrationValues, size_t count);

View File

@ -2,6 +2,7 @@
* @file pm.h * @file pm.h
* @brief Process management (pm*) service IPC wrapper. * @brief Process management (pm*) service IPC wrapper.
* @author plutoo * @author plutoo
* @author yellows8
* @copyright libnx Authors * @copyright libnx Authors
*/ */
#pragma once #pragma once
@ -10,8 +11,13 @@
Result pmdmntInitialize(void); Result pmdmntInitialize(void);
void pmdmntExit(void); void pmdmntExit(void);
Result pmshellInitialize(void);
void pmshellExit(void);
Result pmdmntStartProcess(u64 pid); Result pmdmntStartProcess(u64 pid);
Result pmdmntGetTitlePid(u64* pid_out, u64 title_id); Result pmdmntGetTitlePid(u64* pid_out, u64 title_id);
Result pmdmntEnableDebugForTitleId(Handle* handle_out, u64 title_id); Result pmdmntEnableDebugForTitleId(Handle* handle_out, u64 title_id);
Result pmdmntGetApplicationPid(u64* pid_out); Result pmdmntGetApplicationPid(u64* pid_out);
Result pmdmntEnableDebugForApplication(Handle* handle_out); Result pmdmntEnableDebugForApplication(Handle* handle_out);
Result pmshellLaunchProcess(u32 launch_flags, u64 titleID, u64 storageID, u64 *pid);

View File

@ -34,8 +34,6 @@ 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;
@ -138,7 +136,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, g_gfxPixelFormat, 0x300, &g_gfxCurrentProducerBuffer, fence); rc = bqDequeueBuffer(async, g_gfx_framebuf_width, g_gfx_framebuf_height, 0, 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);
@ -183,7 +181,6 @@ static Result _gfxInit(ViServiceType servicetype, const char *DisplayName, u32 L
g_gfx_drawflip = true; g_gfx_drawflip = true;
g_gfxQueueBufferData.transform = NATIVE_WINDOW_TRANSFORM_FLIP_V; 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));
@ -536,10 +533,6 @@ void gfxConfigureTransform(u32 transform) {
g_gfxQueueBufferData.transform = 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

@ -1,24 +1,41 @@
// Copyright 2017 plutoo // Copyright 2017 plutoo
#include "types.h" #include "types.h"
#include "kernel/detect.h" #include "kernel/detect.h"
#include "kernel/mutex.h"
#include "kernel/svc.h" #include "kernel/svc.h"
static bool g_IsAbove200; static bool g_IsAbove200;
static bool g_IsAbove300; static bool g_IsAbove300;
static bool g_IsAbove400; static bool g_IsAbove400;
static bool g_IsAbove500;
static bool g_HasCached = 0; static bool g_HasCached = 0;
static Mutex g_Mutex;
static void _CacheValues(void) static void _CacheValues(void)
{ {
// This is actually thread safe, might cache twice but that's fine. if (g_HasCached)
if (!g_HasCached) return;
{
mutexLock(&g_Mutex);
if (g_HasCached) {
mutexUnlock(&g_Mutex);
return;
}
u64 tmp; u64 tmp;
g_IsAbove200 = (svcGetInfo(&tmp, 12, INVALID_HANDLE, 0) != 0xF001); g_IsAbove200 = (svcGetInfo(&tmp, 12, INVALID_HANDLE, 0) != 0xF001);
g_IsAbove300 = (svcGetInfo(&tmp, 18, INVALID_HANDLE, 0) != 0xF001); g_IsAbove300 = (svcGetInfo(&tmp, 18, INVALID_HANDLE, 0) != 0xF001);
g_IsAbove400 = (svcGetInfo(&tmp, 19, INVALID_HANDLE, 0) != 0xF001); g_IsAbove400 = (svcGetInfo(&tmp, 19, INVALID_HANDLE, 0) != 0xF001);
g_IsAbove500 = (svcGetInfo(&tmp, 20, INVALID_HANDLE, 0) != 0xF001);
g_IsAbove400 |= g_IsAbove500;
g_IsAbove300 |= g_IsAbove400;
g_IsAbove200 |= g_IsAbove300;
g_HasCached = true; g_HasCached = true;
}
mutexUnlock(&g_Mutex);
} }
bool kernelAbove200(void) { bool kernelAbove200(void) {
@ -36,6 +53,11 @@ bool kernelAbove400(void) {
return g_IsAbove400; return g_IsAbove400;
} }
bool kernelAbove500(void) {
_CacheValues();
return g_IsAbove500;
}
bool detectDebugger(void) { bool detectDebugger(void) {
u64 tmp; u64 tmp;
svcGetInfo(&tmp, 8, 0, 0); svcGetInfo(&tmp, 8, 0, 0);

View File

@ -1,5 +1,8 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <stdlib.h>
#include <netinet/in.h>
#include "result.h" #include "result.h"
#include "runtime/env.h" #include "runtime/env.h"
#include "kernel/svc.h" #include "kernel/svc.h"
@ -7,6 +10,7 @@
// System globals we define here // System globals we define here
int __system_argc; int __system_argc;
char** __system_argv; char** __system_argv;
struct in_addr __nxlink_host;
extern char* fake_heap_start; extern char* fake_heap_start;
extern char* fake_heap_end; extern char* fake_heap_end;
@ -15,6 +19,8 @@ extern u32 __argdata__;
static char* g_argv_empty = NULL; static char* g_argv_empty = NULL;
void nxlinkSetup(void);
void argvSetup(void) void argvSetup(void)
{ {
Result rc=0; Result rc=0;
@ -136,6 +142,12 @@ void argvSetup(void)
__system_argc++; __system_argc++;
} }
// Check for nxlink parameters
nxlinkSetup();
__system_argv[__system_argc] = NULL; __system_argv[__system_argc] = NULL;
} }

View File

@ -553,7 +553,7 @@ int ioctl(int fd, int request, ...) {
if(flags == -1) if(flags == -1)
return -1; return -1;
flags = *(int *)data != 0 ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK); flags = *(int *)data != 0 ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK);
return fcntl(fd, F_SETFL, 0); return fcntl(fd, F_SETFL, flags);
} }
case BIOCSETF: case BIOCSETF:
case BIOCSETWF: case BIOCSETWF:
@ -584,9 +584,35 @@ int ioctl(int fd, int request, ...) {
} }
} }
#define O_NONBLOCK_NX 0x800
#define ALL_NX (O_NONBLOCK_NX)
#define ALL_FLAGS (O_NONBLOCK)
static int from_nx(int flags) {
int newflags = 0;
if(flags & O_NONBLOCK_NX)
newflags |= O_NONBLOCK;
/* add other flag translations here */
return newflags;
}
static int to_nx(int flags) {
int newflags = 0;
if(flags & O_NONBLOCK)
newflags |= O_NONBLOCK_NX;
/* add other flag translations here */
return newflags;
}
int fcntl(int fd, int cmd, ...) { int fcntl(int fd, int cmd, ...) {
va_list args; va_list args;
int flags; int flags=0;
/* /*
bsd:u/s only supports F_GETFL and F_SETFL with the O_NONBLOCK flag (or 0). bsd:u/s only supports F_GETFL and F_SETFL with the O_NONBLOCK flag (or 0).
@ -595,14 +621,30 @@ int fcntl(int fd, int cmd, ...) {
*/ */
if(cmd != F_GETFL && cmd != F_SETFL) if(cmd != F_GETFL && cmd != F_SETFL)
return EOPNOTSUPP; return EOPNOTSUPP;
if (cmd == F_SETFL) {
va_start(args, cmd); va_start(args, cmd);
flags = va_arg(args, int); flags = va_arg(args, int);
va_end(args); va_end(args);
if (flags & ~ALL_FLAGS) {
errno = EINVAL;
return -1;
}
flags = to_nx(flags);
}
fd = _socketGetFd(fd); fd = _socketGetFd(fd);
if(fd == -1) if(fd == -1)
return -1; return -1;
return _socketParseBsdResult(NULL, bsdFcntl(fd, cmd, flags));
flags = _socketParseBsdResult(NULL, bsdFcntl(fd, cmd, flags));
if (flags & ~ALL_NX) {
/* report unknown flags here */
}
return from_nx(flags);
} }
int shutdown(int sockfd, int how) { int shutdown(int sockfd, int how) {
@ -664,7 +706,7 @@ int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, s
/***********************************************************************************************************************/ /***********************************************************************************************************************/
// Adapted from ctrulib // Adapted from libctru
static int _socketInetAtonDetail(int *outBase, size_t *outNumBytes, const char *cp, struct in_addr *inp) { static int _socketInetAtonDetail(int *outBase, size_t *outNumBytes, const char *cp, struct in_addr *inp) {
int base; int base;
u32 val; u32 val;
@ -749,7 +791,7 @@ static int _socketInetAtonDetail(int *outBase, size_t *outNumBytes, const char *
return 1; return 1;
} }
// Adapted from ctrulib // Adapted from libctru
static const char *inet_ntop4(const void *src, char *dst, socklen_t size) { static const char *inet_ntop4(const void *src, char *dst, socklen_t size) {
const u8 *ip = src; const u8 *ip = src;

View File

@ -2,97 +2,173 @@
#include <malloc.h> #include <malloc.h>
#include "types.h" #include "types.h"
#include "result.h" #include "result.h"
#include "kernel/rwlock.h"
#include "services/fatal.h" #include "services/fatal.h"
#include "services/usb.h" #include "services/usb.h"
#include "runtime/devices/usb_comms.h" #include "runtime/devices/usb_comms.h"
#define TOTAL_INTERFACES 4
typedef struct {
RwLock lock, lock_in, lock_out;
bool initialized;
UsbDsInterface* interface;
UsbDsEndpoint *endpoint_in, *endpoint_out;
u8 *endpoint_in_buffer, *endpoint_out_buffer;
} usbCommsInterface;
static bool g_usbCommsInitialized = false; static bool g_usbCommsInitialized = false;
static UsbDsInterface* interface = NULL; static usbCommsInterface g_usbCommsInterfaces[TOTAL_INTERFACES];
static UsbDsEndpoint *g_usbComms_endpoint_in = NULL, *g_usbComms_endpoint_out = NULL;
static u8 *g_usbComms_endpoint_in_buffer = NULL, *g_usbComms_endpoint_out_buffer = NULL; static RwLock g_usbCommsLock;
static Result _usbCommsInit(void); static Result _usbCommsInterfaceInit(usbCommsInterface *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol);
static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferredSize); static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, size_t size, size_t *transferredSize);
Result usbCommsInitializeEx(u32 *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol)
{
bool found=0;
usbCommsInterface *inter = NULL;
rwlockWriteLock(&g_usbCommsLock);
if (g_usbCommsInitialized && interface==NULL) {
rwlockWriteUnlock(&g_usbCommsLock);
return 0;
}
Result rc=0;
u32 i = 0;
if (!g_usbCommsInitialized) rc = usbDsInitialize(UsbComplexId_Default, NULL);
if (R_SUCCEEDED(rc)) {
for(i=0; i<TOTAL_INTERFACES; i++) {
inter = &g_usbCommsInterfaces[i];
rwlockReadLock(&inter->lock);
if (!inter->initialized) found=1;
rwlockReadUnlock(&inter->lock);
if (found) break;
}
if (!found) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
}
if (R_SUCCEEDED(rc)) {
rwlockWriteLock(&inter->lock);
rwlockWriteLock(&inter->lock_in);
rwlockWriteLock(&inter->lock_out);
rc = _usbCommsInterfaceInit(inter, bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol);
rwlockWriteUnlock(&inter->lock_out);
rwlockWriteUnlock(&inter->lock_in);
rwlockWriteUnlock(&inter->lock);
}
if (R_FAILED(rc)) {
usbCommsExit();
}
if (R_SUCCEEDED(rc)) g_usbCommsInitialized=true;
if (R_SUCCEEDED(rc) && interface) *interface = i;
rwlockWriteUnlock(&g_usbCommsLock);
return rc;
}
Result usbCommsInitialize(void) Result usbCommsInitialize(void)
{ {
if (g_usbCommsInitialized) return 0; return usbCommsInitializeEx(NULL, USB_CLASS_VENDOR_SPEC, USB_CLASS_VENDOR_SPEC, USB_CLASS_VENDOR_SPEC);
Result ret=0;
ret = usbDsInitialize(UsbComplexId_Default, NULL);
if (R_SUCCEEDED(ret)) {
//The buffer for PostBufferAsync commands must be 0x1000-byte aligned.
g_usbComms_endpoint_in_buffer = memalign(0x1000, 0x1000);
if (g_usbComms_endpoint_in_buffer==NULL) ret = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
if (R_SUCCEEDED(ret)) {
g_usbComms_endpoint_out_buffer = memalign(0x1000, 0x1000);
if (g_usbComms_endpoint_out_buffer==NULL) ret = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
} }
if (R_SUCCEEDED(ret)) { static void _usbCommsInterfaceExit(usbCommsInterface *interface)
memset(g_usbComms_endpoint_in_buffer, 0, 0x1000); {
memset(g_usbComms_endpoint_out_buffer, 0, 0x1000); rwlockWriteLock(&interface->lock);
ret = _usbCommsInit(); if (!interface->initialized) {
rwlockWriteUnlock(&interface->lock);
if (ret != 0) { return;
ret += 2000<<9;
}
} }
if (R_FAILED(ret)) { rwlockWriteLock(&interface->lock_in);
usbDsExit(); rwlockWriteLock(&interface->lock_out);
free(g_usbComms_endpoint_in_buffer); interface->initialized = 0;
g_usbComms_endpoint_in_buffer = NULL;
free(g_usbComms_endpoint_out_buffer); usbDsInterface_DisableInterface(interface->interface);
g_usbComms_endpoint_out_buffer = NULL; usbDsEndpoint_Close(interface->endpoint_in);
} usbDsEndpoint_Close(interface->endpoint_out);
} usbDsInterface_Close(interface->interface);
else {
ret += 1000<<9; interface->endpoint_in = NULL;
interface->endpoint_out = NULL;
interface->interface = NULL;
free(interface->endpoint_in_buffer);
free(interface->endpoint_out_buffer);
interface->endpoint_in_buffer = NULL;
interface->endpoint_out_buffer = NULL;
rwlockWriteUnlock(&interface->lock_out);
rwlockWriteUnlock(&interface->lock_in);
rwlockWriteUnlock(&interface->lock);
} }
if (R_SUCCEEDED(ret)) g_usbCommsInitialized=true; void usbCommsExitEx(u32 interface)
{
u32 i;
bool found=0;
if (interface>=TOTAL_INTERFACES) return;
return ret; _usbCommsInterfaceExit(&g_usbCommsInterfaces[interface]);
for (i=0; i<TOTAL_INTERFACES; i++)
{
rwlockReadLock(&g_usbCommsInterfaces[i].lock);
if (g_usbCommsInterfaces[i].initialized) found = 1;
rwlockReadUnlock(&g_usbCommsInterfaces[i].lock);
if (found) break;
}
if (!found) usbCommsExit();
} }
void usbCommsExit(void) void usbCommsExit(void)
{ {
if (!g_usbCommsInitialized) return; u32 i;
rwlockWriteLock(&g_usbCommsLock);
usbDsExit(); usbDsExit();
g_usbCommsInitialized = false; g_usbCommsInitialized = false;
g_usbComms_endpoint_in = NULL; rwlockWriteUnlock(&g_usbCommsLock);
g_usbComms_endpoint_out = NULL;
free(g_usbComms_endpoint_in_buffer); for (i=0; i<TOTAL_INTERFACES; i++)
g_usbComms_endpoint_in_buffer = NULL; {
_usbCommsInterfaceExit(&g_usbCommsInterfaces[i]);
free(g_usbComms_endpoint_out_buffer); }
g_usbComms_endpoint_out_buffer = NULL;
} }
static Result _usbCommsInit(void) static Result _usbCommsInterfaceInit(usbCommsInterface *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol)
{ {
Result ret=0; Result rc=0;
struct usb_interface_descriptor interface_descriptor = { struct usb_interface_descriptor interface_descriptor = {
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = USBDS_DEFAULT_InterfaceNumber, .bInterfaceNumber = USBDS_DEFAULT_InterfaceNumber,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceClass = bInterfaceClass,
.bInterfaceSubClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = bInterfaceSubClass,
.bInterfaceProtocol = USB_CLASS_VENDOR_SPEC, .bInterfaceProtocol = bInterfaceProtocol,
}; };
struct usb_endpoint_descriptor endpoint_descriptor_in = { struct usb_endpoint_descriptor endpoint_descriptor_in = {
@ -111,26 +187,44 @@ static Result _usbCommsInit(void)
.wMaxPacketSize = 0x200, .wMaxPacketSize = 0x200,
}; };
//Setup interface. interface->initialized = 1;
ret = usbDsGetDsInterface(&interface, &interface_descriptor, "usb");
if (R_FAILED(ret)) return ret;
//Setup endpoints. //The buffer for PostBufferAsync commands must be 0x1000-byte aligned.
ret = usbDsInterface_GetDsEndpoint(interface, &g_usbComms_endpoint_in, &endpoint_descriptor_in);//device->host interface->endpoint_in_buffer = memalign(0x1000, 0x1000);
if (R_FAILED(ret)) return ret; if (interface->endpoint_in_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
ret = usbDsInterface_GetDsEndpoint(interface, &g_usbComms_endpoint_out, &endpoint_descriptor_out);//host->device if (R_SUCCEEDED(rc)) {
if (R_FAILED(ret)) return ret; interface->endpoint_out_buffer = memalign(0x1000, 0x1000);
if (interface->endpoint_out_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
ret = usbDsInterface_EnableInterface(interface);
if (R_FAILED(ret)) return ret;
return ret;
} }
static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize) if (R_SUCCEEDED(rc)) {
memset(interface->endpoint_in_buffer, 0, 0x1000);
memset(interface->endpoint_out_buffer, 0, 0x1000);
}
if (R_FAILED(rc)) return rc;
//Setup interface.
rc = usbDsGetDsInterface(&interface->interface, &interface_descriptor, "usb");
if (R_FAILED(rc)) return rc;
//Setup endpoints.
rc = usbDsInterface_GetDsEndpoint(interface->interface, &interface->endpoint_in, &endpoint_descriptor_in);//device->host
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_GetDsEndpoint(interface->interface, &interface->endpoint_out, &endpoint_descriptor_out);//host->device
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_EnableInterface(interface->interface);
if (R_FAILED(rc)) return rc;
return rc;
}
static Result _usbCommsRead(usbCommsInterface *interface, void* buffer, size_t size, size_t *transferredSize)
{ {
Result ret=0; Result rc=0;
u32 urbId=0; u32 urbId=0;
u8 *bufptr = (u8*)buffer; u8 *bufptr = (u8*)buffer;
u8 *transfer_buffer = NULL; u8 *transfer_buffer = NULL;
@ -141,15 +235,15 @@ static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize)
usbDsReportData reportdata; usbDsReportData reportdata;
//Makes sure endpoints are ready for data-transfer / wait for init if needed. //Makes sure endpoints are ready for data-transfer / wait for init if needed.
ret = usbDsWaitReady(); rc = usbDsWaitReady();
if (R_FAILED(ret)) return ret; if (R_FAILED(rc)) return rc;
while(size) while(size)
{ {
if(((u64)bufptr) & 0xfff)//When bufptr isn't page-aligned copy the data into g_usbComms_endpoint_in_buffer and transfer that, otherwise use the bufptr directly. if(((u64)bufptr) & 0xfff)//When bufptr isn't page-aligned copy the data into g_usbComms_endpoint_in_buffer and transfer that, otherwise use the bufptr directly.
{ {
transfer_buffer = g_usbComms_endpoint_out_buffer; transfer_buffer = interface->endpoint_out_buffer;
memset(g_usbComms_endpoint_out_buffer, 0, 0x1000); memset(interface->endpoint_out_buffer, 0, 0x1000);
chunksize = 0x1000; chunksize = 0x1000;
chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer). chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer).
@ -166,18 +260,18 @@ static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize)
} }
//Start a host->device transfer. //Start a host->device transfer.
ret = usbDsEndpoint_PostBufferAsync(g_usbComms_endpoint_out, transfer_buffer, chunksize, &urbId); rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_out, transfer_buffer, chunksize, &urbId);
if (R_FAILED(ret)) return ret; if (R_FAILED(rc)) return rc;
//Wait for the transfer to finish. //Wait for the transfer to finish.
svcWaitSynchronizationSingle(g_usbComms_endpoint_out->CompletionEvent, U64_MAX); svcWaitSynchronizationSingle(interface->endpoint_out->CompletionEvent, U64_MAX);
svcClearEvent(g_usbComms_endpoint_out->CompletionEvent); svcClearEvent(interface->endpoint_out->CompletionEvent);
ret = usbDsEndpoint_GetReportData(g_usbComms_endpoint_out, &reportdata); rc = usbDsEndpoint_GetReportData(interface->endpoint_out, &reportdata);
if (R_FAILED(ret)) return ret; if (R_FAILED(rc)) return rc;
ret = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize); rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
if (R_FAILED(ret)) return ret; if (R_FAILED(rc)) return rc;
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize; if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
total_transferredSize+= (size_t)tmp_transferredSize; total_transferredSize+= (size_t)tmp_transferredSize;
@ -191,12 +285,12 @@ static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize)
if (transferredSize) *transferredSize = total_transferredSize; if (transferredSize) *transferredSize = total_transferredSize;
return ret; return rc;
} }
static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferredSize) static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, size_t size, size_t *transferredSize)
{ {
Result ret=0; Result rc=0;
u32 urbId=0; u32 urbId=0;
u32 chunksize=0; u32 chunksize=0;
u8 *bufptr = (u8*)buffer; u8 *bufptr = (u8*)buffer;
@ -206,21 +300,21 @@ static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferre
usbDsReportData reportdata; usbDsReportData reportdata;
//Makes sure endpoints are ready for data-transfer / wait for init if needed. //Makes sure endpoints are ready for data-transfer / wait for init if needed.
ret = usbDsWaitReady(); rc = usbDsWaitReady();
if (R_FAILED(ret)) return ret; if (R_FAILED(rc)) return rc;
while(size) while(size)
{ {
if(((u64)bufptr) & 0xfff)//When bufptr isn't page-aligned copy the data into g_usbComms_endpoint_in_buffer and transfer that, otherwise use the bufptr directly. if(((u64)bufptr) & 0xfff)//When bufptr isn't page-aligned copy the data into g_usbComms_endpoint_in_buffer and transfer that, otherwise use the bufptr directly.
{ {
transfer_buffer = g_usbComms_endpoint_in_buffer; transfer_buffer = interface->endpoint_in_buffer;
memset(g_usbComms_endpoint_in_buffer, 0, 0x1000); memset(interface->endpoint_in_buffer, 0, 0x1000);
chunksize = 0x1000; chunksize = 0x1000;
chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer). chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer).
if (size<chunksize) chunksize = size; if (size<chunksize) chunksize = size;
memcpy(g_usbComms_endpoint_in_buffer, bufptr, chunksize); memcpy(interface->endpoint_in_buffer, bufptr, chunksize);
} }
else else
{ {
@ -229,18 +323,18 @@ static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferre
} }
//Start a device->host transfer. //Start a device->host transfer.
ret = usbDsEndpoint_PostBufferAsync(g_usbComms_endpoint_in, transfer_buffer, chunksize, &urbId); rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_in, transfer_buffer, chunksize, &urbId);
if(R_FAILED(ret))return ret; if(R_FAILED(rc))return rc;
//Wait for the transfer to finish. //Wait for the transfer to finish.
svcWaitSynchronizationSingle(g_usbComms_endpoint_in->CompletionEvent, U64_MAX); svcWaitSynchronizationSingle(interface->endpoint_in->CompletionEvent, U64_MAX);
svcClearEvent(g_usbComms_endpoint_in->CompletionEvent); svcClearEvent(interface->endpoint_in->CompletionEvent);
ret = usbDsEndpoint_GetReportData(g_usbComms_endpoint_in, &reportdata); rc = usbDsEndpoint_GetReportData(interface->endpoint_in, &reportdata);
if (R_FAILED(ret)) return ret; if (R_FAILED(rc)) return rc;
ret = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize); rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
if (R_FAILED(ret)) return ret; if (R_FAILED(rc)) return rc;
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize; if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
@ -254,38 +348,80 @@ static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferre
if (transferredSize) *transferredSize = total_transferredSize; if (transferredSize) *transferredSize = total_transferredSize;
return ret; return rc;
}
size_t usbCommsReadEx(void* buffer, size_t size, u32 interface)
{
size_t transferredSize=0;
u32 state=0;
Result rc, rc2;
usbCommsInterface *inter = &g_usbCommsInterfaces[interface];
bool initialized;
if (interface>=TOTAL_INTERFACES) return 0;
rwlockReadLock(&inter->lock);
initialized = inter->initialized;
rwlockReadUnlock(&inter->lock);
if (!initialized) return 0;
rwlockWriteLock(&inter->lock_out);
rc = _usbCommsRead(inter, buffer, size, &transferredSize);
rwlockWriteUnlock(&inter->lock_out);
if (R_FAILED(rc)) {
rc2 = usbDsGetState(&state);
if (R_SUCCEEDED(rc2)) {
if (state!=5) {
rwlockWriteLock(&inter->lock_out);
rc = _usbCommsRead(&g_usbCommsInterfaces[interface], buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this.
rwlockWriteUnlock(&inter->lock_out);
}
}
if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsRead));
}
return transferredSize;
} }
size_t usbCommsRead(void* buffer, size_t size) size_t usbCommsRead(void* buffer, size_t size)
{
return usbCommsReadEx(buffer, size, 0);
}
size_t usbCommsWriteEx(const void* buffer, size_t size, u32 interface)
{ {
size_t transferredSize=0; size_t transferredSize=0;
u32 state=0; u32 state=0;
Result ret, ret2; Result rc, rc2;
ret = _usbCommsRead(buffer, size, &transferredSize); usbCommsInterface *inter = &g_usbCommsInterfaces[interface];
if (R_FAILED(ret)) { bool initialized;
ret2 = usbDsGetState(&state);
if (R_SUCCEEDED(ret2)) { if (interface>=TOTAL_INTERFACES) return 0;
if (state!=5) ret = _usbCommsRead(buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this.
rwlockReadLock(&inter->lock);
initialized = inter->initialized;
rwlockReadUnlock(&inter->lock);
if (!initialized) return 0;
rwlockWriteLock(&inter->lock_in);
rc = _usbCommsWrite(&g_usbCommsInterfaces[interface], buffer, size, &transferredSize);
rwlockWriteUnlock(&inter->lock_in);
if (R_FAILED(rc)) {
rc2 = usbDsGetState(&state);
if (R_SUCCEEDED(rc2)) {
if (state!=5) {
rwlockWriteLock(&inter->lock_in);
rc = _usbCommsWrite(&g_usbCommsInterfaces[interface], buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this.
rwlockWriteUnlock(&inter->lock_in);
} }
if (R_FAILED(ret))fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsRead)); }
if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsWrite));
} }
return transferredSize; return transferredSize;
} }
size_t usbCommsWrite(const void* buffer, size_t size) size_t usbCommsWrite(const void* buffer, size_t size)
{ {
size_t transferredSize=0; return usbCommsWriteEx(buffer, size, 0);
u32 state=0;
Result ret, ret2;
ret = _usbCommsWrite(buffer, size, &transferredSize);
if (R_FAILED(ret)) {
ret2 = usbDsGetState(&state);
if (R_SUCCEEDED(ret2)) {
if (state!=5) ret = _usbCommsWrite(buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this.
}
if (R_FAILED(ret))fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsWrite));
}
return transferredSize;
} }

View File

@ -16,6 +16,7 @@ static u64 g_syscallHints[2];
static Handle g_processHandle = INVALID_HANDLE; static Handle g_processHandle = INVALID_HANDLE;
static char* g_nextLoadPath = NULL; static char* g_nextLoadPath = NULL;
static char* g_nextLoadArgv = NULL; static char* g_nextLoadArgv = NULL;
static Result g_lastLoadResult = 0;
extern __attribute__((weak)) u32 __nx_applet_type; extern __attribute__((weak)) u32 __nx_applet_type;
@ -84,6 +85,10 @@ void envSetup(void* ctx, Handle main_thread, LoaderReturnFn saved_lr)
g_processHandle = ent->Value[0]; g_processHandle = ent->Value[0];
break; break;
case EntryType_LastLoadResult:
g_lastLoadResult = ent->Value[0];
break;
default: default:
if (ent->Flags & EntryFlag_IsMandatory) if (ent->Flags & EntryFlag_IsMandatory)
{ {
@ -164,3 +169,7 @@ Result envSetNextLoad(const char* path, const char* argv)
bool envHasNextLoad(void) { bool envHasNextLoad(void) {
return g_nextLoadPath != NULL; return g_nextLoadPath != NULL;
} }
Result envGetLastLoadResult(void) {
return g_lastLoadResult;
}

View File

@ -0,0 +1,23 @@
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
// System globals we define here
extern int __system_argc;
extern char** __system_argv;
struct in_addr __nxlink_host;
void nxlinkSetup(void)
{
if ( __system_argc > 1 &&
strlen(__system_argv[__system_argc - 1]) == 16 &&
strncmp(&__system_argv[__system_argc - 1][8], "_NXLINK_", 8) == 0 )
{
__system_argc--;
__nxlink_host.s_addr = strtoul(__system_argv[__system_argc], NULL, 16);
}
__system_argv[__system_argc] = NULL;
}

View File

@ -1,3 +1,5 @@
#include <string.h>
#include "types.h" #include "types.h"
#include "arm/atomics.h" #include "arm/atomics.h"
#include "services/acc.h" #include "services/acc.h"
@ -8,12 +10,17 @@ static u64 g_refCnt;
Result accountInitialize(void) Result accountInitialize(void)
{ {
Result rc=0;
atomicIncrement64(&g_refCnt); atomicIncrement64(&g_refCnt);
if (serviceIsActive(&g_accSrv)) if (serviceIsActive(&g_accSrv))
return 0; return 0;
return smGetService(&g_accSrv, "acc:u1"); rc = smGetService(&g_accSrv, "acc:u1");
if (R_FAILED(rc)) rc = smGetService(&g_accSrv, "acc:u0");
return rc;
} }
void accountExit(void) void accountExit(void)
@ -67,3 +74,153 @@ Result accountGetActiveUser(u128 *userID, bool *account_selected)
return rc; return rc;
} }
Result accountGetProfile(AccountProfile* out, u128 userID) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u128 userID;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 5;
raw->userID = userID;
Result rc = serviceIpcDispatch(&g_accSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
serviceCreate(&out->s, r.Handles[0]);
}
}
return rc;
}
//IProfile implementation
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) {
IpcCommand c;
ipcInitialize(&c);
if (userdata) ipcAddRecvStatic(&c, userdata, sizeof(AccountUserData), 0);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = userdata==NULL ? 1 : 0;
Result rc = serviceIpcDispatch(&profile->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
AccountProfileBase profilebase;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && profilebase) memcpy(profilebase, &resp->profilebase, sizeof(AccountProfileBase));
}
return rc;
}
Result accountProfileGetImageSize(AccountProfile* profile, size_t* image_size) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 10;
Result rc = serviceIpcDispatch(&profile->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 image_size;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*image_size = resp->image_size;
}
}
return rc;
}
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, size_t* image_size) {
IpcCommand c;
ipcInitialize(&c);
ipcAddRecvBuffer(&c, buf, len, 0);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 11;
Result rc = serviceIpcDispatch(&profile->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 image_size;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*image_size = resp->image_size;
}
}
return rc;
}
void accountProfileClose(AccountProfile* profile) {
serviceClose(&profile->s);
}

View File

@ -92,7 +92,7 @@ Result fsMountSdcard(FsFileSystem* out) {
rc = resp->result; rc = resp->result;
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
out->h = r.Handles[0]; serviceCreate(&out->s, r.Handles[0]);
} }
} }
@ -131,7 +131,96 @@ Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save) {
rc = resp->result; rc = resp->result;
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
out->h = r.Handles[0]; serviceCreate(&out->s, r.Handles[0]);
}
}
return rc;
}
Result fsMountSystemSaveData(FsFileSystem* out, u8 inval, FsSave *save) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 inval;//Actually u8.
FsSave save;
} PACKED *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 52;
raw->inval = (u64)inval;
memcpy(&raw->save, save, sizeof(FsSave));
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)) {
serviceCreate(&out->s, r.Handles[0]);
}
}
return rc;
}
Result fsOpenSaveDataIterator(FsSaveDataIterator* out, s32 SaveDataSpaceId) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
struct {
u64 magic;
u64 cmd_id;
u8 SaveDataSpaceId;
} *raw2;
if (SaveDataSpaceId == FsSaveDataSpaceId_All) {
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 60;
}
else {
raw2 = ipcPrepareHeader(&c, sizeof(*raw2));
raw2->magic = SFCI_MAGIC;
raw2->cmd_id = 61;
raw2->SaveDataSpaceId = SaveDataSpaceId;
}
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)) {
serviceCreate(&out->s, r.Handles[0]);
} }
} }
@ -166,7 +255,7 @@ Result fsOpenDataStorageByCurrentProcess(FsStorage* out) {
rc = resp->result; rc = resp->result;
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
out->h = r.Handles[0]; serviceCreate(&out->s, r.Handles[0]);
} }
} }
@ -180,9 +269,19 @@ Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID) {
memset(&save, 0, sizeof(save)); memset(&save, 0, sizeof(save));
save.titleID = titleID; save.titleID = titleID;
save.userID = userID; save.userID = userID;
save.ContentStorageId = FS_CONTENTSTORAGEID_NandUser; save.SaveDataType = FsSaveDataType_SaveData;
return fsMountSaveData(out, FS_MOUNTSAVEDATA_INVAL_DEFAULT, &save); return fsMountSaveData(out, FsSaveDataSpaceId_NandUser, &save);
}
Result fsMount_SystemSaveData(FsFileSystem* out, u64 saveID) {
FsSave save;
memset(&save, 0, sizeof(save));
save.saveID = saveID;
save.SaveDataType = FsSaveDataType_SystemSaveData;
return fsMountSystemSaveData(out, FsSaveDataSpaceId_NandSystem, &save);
} }
// IFileSystem impl // IFileSystem impl
@ -207,7 +306,7 @@ Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags
raw->size = size; raw->size = size;
raw->flags = flags; raw->flags = flags;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -239,7 +338,7 @@ Result fsFsDeleteFile(FsFileSystem* fs, const char* path) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 1; raw->cmd_id = 1;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -271,7 +370,7 @@ Result fsFsCreateDirectory(FsFileSystem* fs, const char* path) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 2; raw->cmd_id = 2;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -303,7 +402,7 @@ Result fsFsDeleteDirectory(FsFileSystem* fs, const char* path) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 3; raw->cmd_id = 3;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -335,7 +434,7 @@ Result fsFsDeleteDirectoryRecursively(FsFileSystem* fs, const char* path) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 4; raw->cmd_id = 4;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -368,7 +467,7 @@ Result fsFsRenameFile(FsFileSystem* fs, const char* path0, const char* path1) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 5; raw->cmd_id = 5;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -401,7 +500,7 @@ Result fsFsRenameDirectory(FsFileSystem* fs, const char* path0, const char* path
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 6; raw->cmd_id = 6;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -433,7 +532,7 @@ Result fsFsGetEntryType(FsFileSystem* fs, const char* path, FsEntryType* out) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 7; raw->cmd_id = 7;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -472,7 +571,7 @@ Result fsFsOpenFile(FsFileSystem* fs, const char* path, int flags, FsFile* out)
raw->cmd_id = 8; raw->cmd_id = 8;
raw->flags = flags; raw->flags = flags;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -486,7 +585,7 @@ Result fsFsOpenFile(FsFileSystem* fs, const char* path, int flags, FsFile* out)
rc = resp->result; rc = resp->result;
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
out->h = r.Handles[0]; serviceCreate(&out->s, r.Handles[0]);
} }
} }
@ -510,7 +609,7 @@ Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, int flags, FsDir* o
raw->cmd_id = 9; raw->cmd_id = 9;
raw->flags = flags; raw->flags = flags;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -524,7 +623,7 @@ Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, int flags, FsDir* o
rc = resp->result; rc = resp->result;
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
out->h = r.Handles[0]; serviceCreate(&out->s, r.Handles[0]);
} }
} }
@ -545,7 +644,7 @@ Result fsFsCommit(FsFileSystem* fs) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 10; raw->cmd_id = 10;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -577,7 +676,7 @@ Result fsFsGetFreeSpace(FsFileSystem* fs, const char* path, u64* out) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 11; raw->cmd_id = 11;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -614,7 +713,7 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 12; raw->cmd_id = 12;
Result rc = ipcDispatch(fs->h); Result rc = serviceIpcDispatch(&fs->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -637,7 +736,7 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
} }
void fsFsClose(FsFileSystem* fs) { void fsFsClose(FsFileSystem* fs) {
if(fs->h != INVALID_HANDLE) svcCloseHandle(fs->h); serviceClose(&fs->s);
} }
// IFile implementation // IFile implementation
@ -662,7 +761,7 @@ Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, size_t* out) {
raw->offset = off; raw->offset = off;
raw->read_size = len; raw->read_size = len;
Result rc = ipcDispatch(f->h); Result rc = serviceIpcDispatch(&f->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -705,7 +804,7 @@ Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len) {
raw->offset = off; raw->offset = off;
raw->write_size = len; raw->write_size = len;
Result rc = ipcDispatch(f->h); Result rc = serviceIpcDispatch(&f->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -736,7 +835,7 @@ Result fsFileFlush(FsFile* f) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 2; raw->cmd_id = 2;
Result rc = ipcDispatch(f->h); Result rc = serviceIpcDispatch(&f->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -769,7 +868,7 @@ Result fsFileSetSize(FsFile* f, u64 sz) {
raw->cmd_id = 3; raw->cmd_id = 3;
raw->size = sz; raw->size = sz;
Result rc = ipcDispatch(f->h); Result rc = serviceIpcDispatch(&f->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -800,7 +899,7 @@ Result fsFileGetSize(FsFile* f, u64* out) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 4; raw->cmd_id = 4;
Result rc = ipcDispatch(f->h); Result rc = serviceIpcDispatch(&f->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -820,12 +919,12 @@ Result fsFileGetSize(FsFile* f, u64* out) {
} }
void fsFileClose(FsFile* f) { void fsFileClose(FsFile* f) {
if(f->h != INVALID_HANDLE) svcCloseHandle(f->h); serviceClose(&f->s);
} }
// IDirectory implementation // IDirectory implementation
void fsDirClose(FsDir* d) { void fsDirClose(FsDir* d) {
if(d->h != INVALID_HANDLE) svcCloseHandle(d->h); serviceClose(&d->s);
} }
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) {
@ -845,7 +944,7 @@ Result fsDirRead(FsDir* d, u64 inval, size_t* total_entries, size_t max_entries,
raw->cmd_id = 0; raw->cmd_id = 0;
raw->inval = inval; raw->inval = inval;
Result rc = ipcDispatch(d->h); Result rc = serviceIpcDispatch(&d->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -881,7 +980,7 @@ Result fsDirGetEntryCount(FsDir* d, u64* count) {
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 1; raw->cmd_id = 1;
Result rc = ipcDispatch(d->h); Result rc = serviceIpcDispatch(&d->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -920,7 +1019,7 @@ Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len) {
raw->offset = off; raw->offset = off;
raw->read_size = len; raw->read_size = len;
Result rc = ipcDispatch(s->h); Result rc = serviceIpcDispatch(&s->s);
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
IpcParsedCommand r; IpcParsedCommand r;
@ -938,6 +1037,48 @@ Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len) {
} }
void fsStorageClose(FsStorage* s) { void fsStorageClose(FsStorage* s) {
if(s->h != INVALID_HANDLE) svcCloseHandle(s->h); serviceClose(&s->s);
}
// ISaveDataInfoReader
Result fsSaveDataIteratorRead(FsSaveDataIterator *s, FsSaveDataInfo* buf, size_t max_entries, size_t* total_entries) {
IpcCommand c;
ipcInitialize(&c);
ipcAddRecvBuffer(&c, buf, sizeof(FsSaveDataInfo)*max_entries, 0);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
Result rc = serviceIpcDispatch(&s->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 total_entries;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (total_entries) *total_entries = resp->total_entries;
}
}
return rc;
}
void fsSaveDataIteratorClose(FsSaveDataIterator* s) {
serviceClose(&s->s);
} }

View File

@ -375,6 +375,10 @@ void hidJoystickRead(JoystickPosition *pos, HidControllerID id, HidControllerJoy
} }
} }
bool hidGetHandheldMode(void) {
return g_controllerP1AutoID == CONTROLLER_HANDHELD;
}
static Result _hidSetDualModeAll(void) { static Result _hidSetDualModeAll(void) {
Result rc; Result rc;
int i; int i;
@ -731,26 +735,87 @@ Result hidIsVibrationPermitted(bool *flag) {
return rc; return rc;
} }
Result hidInitializeVibrationDevices(u32 *VibrationDeviceHandles, size_t total_handles, HidControllerID id, HidControllerLayoutType type) { Result hidSendVibrationValues(u32 *VibrationDeviceHandles, HidVibrationValue *VibrationValues, size_t count) {
Result rc;
u64 AppletResourceUserId;
rc = appletGetAppletResourceUserId(&AppletResourceUserId);
if (R_FAILED(rc))
return rc;
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 AppletResourceUserId;
} *raw;
ipcAddSendStatic(&c, VibrationDeviceHandles, sizeof(u32)*count, 0);
ipcAddSendStatic(&c, VibrationValues, sizeof(HidVibrationValue)*count, 0);
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 206;
raw->AppletResourceUserId = AppletResourceUserId;
rc = serviceIpcDispatch(&g_hidSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result hidInitializeVibrationDevices(u32 *VibrationDeviceHandles, size_t total_handles, HidControllerID id, HidControllerType type) {
Result rc=0; Result rc=0;
Service srv; Service srv;
u32 tmp_type = type & 0xff; u32 tmp_type = type & 0xff;
u32 tmp_id = id;
size_t i; size_t i;
if (total_handles == 0 || total_handles > 2) if (total_handles == 0 || total_handles > 2)
return MAKERESULT(Module_Libnx, LibnxError_BadInput); return MAKERESULT(Module_Libnx, LibnxError_BadInput);
if (tmp_type < 5) { if (tmp_id == CONTROLLER_HANDHELD)
if (tmp_type == 4) tmp_type |= 0x010000; tmp_id = 0x20;
tmp_type+= 3;
if (tmp_type & LAYOUT_PROCONTROLLER) {
tmp_type = 3;
} }
else { else if (tmp_type & TYPE_HANDHELD) {
if (tmp_type == 5) tmp_type = 0x20; tmp_type = 4;
if (tmp_type == 6) tmp_type = 0x21; }
else if (tmp_type & TYPE_JOYCON_PAIR) {
tmp_type = 5;
}
else if (tmp_type & TYPE_JOYCON_LEFT) {
tmp_type = 6;
}
else if (tmp_type & TYPE_JOYCON_RIGHT) {
tmp_type = 7;
tmp_type |= 0x010000;
}
//The HidControllerID enum doesn't have bit29/bit30 checked by official sw, for tmp_type 0x20/0x21.
else if (tmp_type & BIT(29)) {
tmp_type = 0x20;
}
else if (tmp_type & BIT(30)) {
tmp_type = 0x21;
} }
//TODO: Is type correct? VibrationDeviceHandles[0] = tmp_type | (tmp_id & 0xff)<<8;
VibrationDeviceHandles[0] = tmp_type | (id & 0xff)<<8;
if (total_handles > 1) { if (total_handles > 1) {
tmp_type &= 0xff; tmp_type &= 0xff;

View File

@ -6,12 +6,12 @@
#include "services/pm.h" #include "services/pm.h"
#include "services/sm.h" #include "services/sm.h"
static Service g_pmdmntSrv; static Service g_pmdmntSrv, g_pmshellSrv;
static u64 g_refCnt; static u64 g_pmdmntRefCnt, g_pmshellRefCnt;
Result pmdmntInitialize(void) Result pmdmntInitialize(void)
{ {
atomicIncrement64(&g_refCnt); atomicIncrement64(&g_pmdmntRefCnt);
if (serviceIsActive(&g_pmdmntSrv)) if (serviceIsActive(&g_pmdmntSrv))
return 0; return 0;
@ -21,11 +21,28 @@ Result pmdmntInitialize(void)
void pmdmntExit(void) void pmdmntExit(void)
{ {
if (atomicDecrement64(&g_refCnt) == 0) { if (atomicDecrement64(&g_pmdmntRefCnt) == 0) {
serviceClose(&g_pmdmntSrv); serviceClose(&g_pmdmntSrv);
} }
} }
Result pmshellInitialize(void)
{
atomicIncrement64(&g_pmshellRefCnt);
if (serviceIsActive(&g_pmshellSrv))
return 0;
return smGetService(&g_pmshellSrv, "pm:shell");
}
void pmshellExit(void)
{
if (atomicDecrement64(&g_pmshellRefCnt) == 0) {
serviceClose(&g_pmshellSrv);
}
}
Result pmdmntStartProcess(u64 pid) { Result pmdmntStartProcess(u64 pid) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
@ -204,3 +221,43 @@ Result pmdmntEnableDebugForApplication(Handle* handle_out) {
return rc; return rc;
} }
Result pmshellLaunchProcess(u32 launch_flags, u64 titleID, u64 storageID, u64 *pid) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 launch_flags;
u64 titleID;
u64 storageID;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 0;
raw->launch_flags = launch_flags;
raw->titleID = titleID;
raw->storageID = storageID;
Result rc = serviceIpcDispatch(&g_pmshellSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 pid;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && pid) *pid = resp->pid;
}
return rc;
}

View File

@ -5,6 +5,7 @@ endif
include $(DEVKITPRO)/devkitA64/base_rules include $(DEVKITPRO)/devkitA64/base_rules
PORTLIBS := $(PORTLIBS_PATH)/switch PORTLIBS := $(PORTLIBS_PATH)/switch
PATH := $(PORTLIBS)/bin:$(PATH)
LIBNX ?= $(DEVKITPRO)/libnx LIBNX ?= $(DEVKITPRO)/libnx