mirror of
https://github.com/switchbrew/libnx.git
synced 2025-07-04 10:32:15 +02:00
Merge remote-tracking branch 'origin/master' into gpu
This commit is contained in:
commit
1e51ea6662
32
nx/external/bsd/include/netinet/in.h
vendored
32
nx/external/bsd/include/netinet/in.h
vendored
@ -588,37 +588,37 @@ struct group_source_req {
|
||||
* Unspecified
|
||||
*/
|
||||
#define IN6_IS_ADDR_UNSPECIFIED(a) \
|
||||
((a)->__u6_addr.__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[2] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[3] == 0)
|
||||
((a)->__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr32[2] == 0 && \
|
||||
(a)->__u6_addr32[3] == 0)
|
||||
|
||||
/*
|
||||
* Loopback
|
||||
*/
|
||||
#define IN6_IS_ADDR_LOOPBACK(a) \
|
||||
((a)->__u6_addr.__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[2] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[3] == ntohl(1))
|
||||
((a)->__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr32[2] == 0 && \
|
||||
(a)->__u6_addr32[3] == ntohl(1))
|
||||
|
||||
/*
|
||||
* IPv4 compatible
|
||||
*/
|
||||
#define IN6_IS_ADDR_V4COMPAT(a) \
|
||||
((a)->__u6_addr.__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[2] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[3] != 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[3] != ntohl(1))
|
||||
((a)->__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr32[2] == 0 && \
|
||||
(a)->__u6_addr32[3] != 0 && \
|
||||
(a)->__u6_addr32[3] != ntohl(1))
|
||||
|
||||
/*
|
||||
* Mapped
|
||||
*/
|
||||
#define IN6_IS_ADDR_V4MAPPED(a) \
|
||||
((a)->__u6_addr.__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr.__u6_addr32[2] == ntohl(0x0000ffff))
|
||||
((a)->__u6_addr32[0] == 0 && \
|
||||
(a)->__u6_addr32[1] == 0 && \
|
||||
(a)->__u6_addr32[2] == ntohl(0x0000ffff))
|
||||
|
||||
#define __IPV6_ADDR_SCOPE_NODELOCAL 0x01
|
||||
#define __IPV6_ADDR_SCOPE_INTFACELOCAL 0x01
|
||||
|
@ -78,6 +78,7 @@ extern "C" {
|
||||
#include "switch/nvidia/cmds/3d_clear.h"
|
||||
|
||||
#include "switch/runtime/env.h"
|
||||
#include "switch/runtime/nxlink.h"
|
||||
|
||||
#include "switch/runtime/util/utf.h"
|
||||
|
||||
|
@ -13,5 +13,7 @@ bool kernelAbove200(void);
|
||||
bool kernelAbove300(void);
|
||||
/// Returns true if the kernel version is equal to or above 4.0.0.
|
||||
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.
|
||||
bool detectDebugger(void);
|
||||
|
@ -395,7 +395,7 @@ static inline Result ipcParse(IpcParsedCommand* r) {
|
||||
|
||||
r->Buffers[i] = (void*) (desc->Addr | ((packed >> 28) << 32) | (((packed >> 2) & 15) << 36));
|
||||
r->BufferSizes[i] = desc->Size;
|
||||
r->BufferTypes[i] = packed & 3;
|
||||
r->BufferTypes[i] = (BufferType) (packed & 3);
|
||||
|
||||
if (i < num_bufs_send)
|
||||
r->BufferDirections[i] = BufferDirection_Send;
|
||||
|
@ -11,5 +11,21 @@
|
||||
Result usbCommsInitialize(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);
|
||||
|
||||
/// Write data with the default interface.
|
||||
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);
|
||||
|
@ -85,3 +85,6 @@ Result envSetNextLoad(const char* path, const char* argv);
|
||||
|
||||
/// Returns true if the environment supports envSetNextLoad.
|
||||
bool envHasNextLoad(void);
|
||||
|
||||
/// Returns the Result from the last NRO.
|
||||
Result envGetLastLoadResult(void);
|
||||
|
8
nx/include/switch/runtime/nxlink.h
Normal file
8
nx/include/switch/runtime/nxlink.h
Normal 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
|
@ -8,9 +8,45 @@
|
||||
#include "../types.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);
|
||||
void accountExit(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.
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file fs.h
|
||||
* @brief Filesystem (fsp-srv) service IPC wrapper.
|
||||
* Normally applications should just use standard stdio not FS-serv directly. However this can be used if obtaining a FsFileSystem, FsFile, or FsStorage, for mounting with fs_dev/romfs_dev.
|
||||
* 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 yellows8
|
||||
* @copyright libnx Authors
|
||||
@ -14,31 +14,32 @@
|
||||
|
||||
#define FS_MAX_PATH 0x301
|
||||
|
||||
/// For use with fsMountSaveData().
|
||||
#define FS_MOUNTSAVEDATA_INVAL_DEFAULT 0x1
|
||||
|
||||
/// For use with FsSave.
|
||||
#define FS_SAVEDATA_CURRENT_TITLEID 0
|
||||
|
||||
/// For use with FsSave.
|
||||
/// For use with \ref FsSave and \ref FsSaveDataInfo.
|
||||
#define FS_SAVEDATA_USERID_COMMONSAVE 0
|
||||
|
||||
typedef struct {
|
||||
Handle h;
|
||||
Service s;
|
||||
} FsFileSystem;
|
||||
|
||||
typedef struct {
|
||||
Handle h;
|
||||
Service s;
|
||||
} FsFile;
|
||||
|
||||
typedef struct {
|
||||
Handle h;
|
||||
Service s;
|
||||
} FsDir;
|
||||
|
||||
typedef struct {
|
||||
Handle h;
|
||||
Service s;
|
||||
} FsStorage;
|
||||
|
||||
typedef struct {
|
||||
Service s;
|
||||
} FsSaveDataIterator;
|
||||
|
||||
/// Directory entry.
|
||||
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.
|
||||
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 ContentStorageId; ///< ContentStorageId? See FsContentStorageId.
|
||||
u64 SaveDataType; ///< See \ref FsSaveDataType.
|
||||
u64 unk_x28; ///< 0 for SystemSaveData/SaveData.
|
||||
u64 unk_x30; ///< 0 for SystemSaveData/SaveData.
|
||||
u64 unk_x38; ///< 0 for SystemSaveData/SaveData.
|
||||
} 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 {
|
||||
ENTRYTYPE_DIR = 0,
|
||||
ENTRYTYPE_FILE = 1
|
||||
@ -80,6 +94,16 @@ typedef enum
|
||||
FS_DIROPEN_FILE = BIT(1), ///< Enable reading file entries.
|
||||
} FsDirectoryFlags;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FsStorageId_None = 0,
|
||||
FsStorageId_Host = 1,
|
||||
FsStorageId_GameCard = 2,
|
||||
FsStorageId_NandSystem = 3,
|
||||
FsStorageId_NandUser = 4,
|
||||
FsStorageId_SdCard = 5,
|
||||
} FsStorageId;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FS_CONTENTSTORAGEID_NandSystem = 0,
|
||||
@ -87,6 +111,26 @@ typedef enum
|
||||
FS_CONTENTSTORAGEID_SdCard = 2,
|
||||
} 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);
|
||||
void fsExit(void);
|
||||
|
||||
@ -96,6 +140,8 @@ Service* fsGetServiceSession(void);
|
||||
Result fsMountSdcard(FsFileSystem* out);
|
||||
|
||||
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);
|
||||
// todo: Rest of commands here
|
||||
|
||||
@ -105,6 +151,10 @@ Result fsOpenDataStorageByCurrentProcess(FsStorage* out);
|
||||
/// See FsSave for titleID and 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
|
||||
Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags);
|
||||
Result fsFsDeleteFile(FsFileSystem* fs, const char* path);
|
||||
@ -137,3 +187,9 @@ void fsDirClose(FsDir* d);
|
||||
// IStorage
|
||||
Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len);
|
||||
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);
|
||||
|
@ -310,7 +310,7 @@ typedef enum
|
||||
CONTROLLER_PLAYER_8 = 7,
|
||||
CONTROLLER_HANDHELD = 8,
|
||||
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;
|
||||
|
||||
typedef struct touchPosition
|
||||
@ -581,17 +581,23 @@ void hidTouchRead(touchPosition *pos, u32 point_id);
|
||||
|
||||
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_*.
|
||||
/// 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_*.
|
||||
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.
|
||||
/// 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_*.
|
||||
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);
|
||||
|
||||
/// 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.
|
||||
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);
|
||||
|
@ -2,6 +2,7 @@
|
||||
* @file pm.h
|
||||
* @brief Process management (pm*) service IPC wrapper.
|
||||
* @author plutoo
|
||||
* @author yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
@ -10,8 +11,13 @@
|
||||
Result pmdmntInitialize(void);
|
||||
void pmdmntExit(void);
|
||||
|
||||
Result pmshellInitialize(void);
|
||||
void pmshellExit(void);
|
||||
|
||||
Result pmdmntStartProcess(u64 pid);
|
||||
Result pmdmntGetTitlePid(u64* pid_out, u64 title_id);
|
||||
Result pmdmntEnableDebugForTitleId(Handle* handle_out, u64 title_id);
|
||||
Result pmdmntGetApplicationPid(u64* pid_out);
|
||||
Result pmdmntEnableDebugForApplication(Handle* handle_out);
|
||||
|
||||
Result pmshellLaunchProcess(u32 launch_flags, u64 titleID, u64 storageID, u64 *pid);
|
||||
|
@ -34,8 +34,6 @@ static GfxMode g_gfxMode = GfxMode_LinearDouble;
|
||||
|
||||
static u8 *g_gfxFramebufLinear;
|
||||
|
||||
static s32 g_gfxPixelFormat = 0;
|
||||
|
||||
size_t g_gfx_framebuf_width=0, g_gfx_framebuf_aligned_width=0;
|
||||
size_t g_gfx_framebuf_height=0, g_gfx_framebuf_aligned_height=0;
|
||||
size_t g_gfx_framebuf_display_width=0, g_gfx_framebuf_display_height=0;
|
||||
@ -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.
|
||||
|
||||
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.
|
||||
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_gfxQueueBufferData.transform = NATIVE_WINDOW_TRANSFORM_FLIP_V;
|
||||
g_gfxPixelFormat = 0;
|
||||
|
||||
memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested));
|
||||
memset(&g_gfx_DequeueBuffer_fence, 0, sizeof(g_gfx_DequeueBuffer_fence));
|
||||
@ -536,10 +533,6 @@ void gfxConfigureTransform(u32 transform) {
|
||||
g_gfxQueueBufferData.transform = transform;
|
||||
}
|
||||
|
||||
/*void gfxSetPixelFormat(s32 format) {
|
||||
g_gfxPixelFormat = format;
|
||||
}*/
|
||||
|
||||
void gfxFlushBuffers(void) {
|
||||
u32 *actual_framebuf = (u32*)&g_gfxFramebuf[g_gfxCurrentBuffer*g_gfx_singleframebuf_size];
|
||||
|
||||
|
@ -1,24 +1,41 @@
|
||||
// Copyright 2017 plutoo
|
||||
#include "types.h"
|
||||
#include "kernel/detect.h"
|
||||
#include "kernel/mutex.h"
|
||||
#include "kernel/svc.h"
|
||||
|
||||
static bool g_IsAbove200;
|
||||
static bool g_IsAbove300;
|
||||
static bool g_IsAbove400;
|
||||
static bool g_IsAbove500;
|
||||
static bool g_HasCached = 0;
|
||||
static Mutex g_Mutex;
|
||||
|
||||
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;
|
||||
g_IsAbove200 = (svcGetInfo(&tmp, 12, INVALID_HANDLE, 0) != 0xF001);
|
||||
g_IsAbove300 = (svcGetInfo(&tmp, 18, 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;
|
||||
}
|
||||
|
||||
mutexUnlock(&g_Mutex);
|
||||
}
|
||||
|
||||
bool kernelAbove200(void) {
|
||||
@ -36,6 +53,11 @@ bool kernelAbove400(void) {
|
||||
return g_IsAbove400;
|
||||
}
|
||||
|
||||
bool kernelAbove500(void) {
|
||||
_CacheValues();
|
||||
return g_IsAbove500;
|
||||
}
|
||||
|
||||
bool detectDebugger(void) {
|
||||
u64 tmp;
|
||||
svcGetInfo(&tmp, 8, 0, 0);
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "result.h"
|
||||
#include "runtime/env.h"
|
||||
#include "kernel/svc.h"
|
||||
@ -7,6 +10,7 @@
|
||||
// System globals we define here
|
||||
int __system_argc;
|
||||
char** __system_argv;
|
||||
struct in_addr __nxlink_host;
|
||||
|
||||
extern char* fake_heap_start;
|
||||
extern char* fake_heap_end;
|
||||
@ -15,6 +19,8 @@ extern u32 __argdata__;
|
||||
|
||||
static char* g_argv_empty = NULL;
|
||||
|
||||
void nxlinkSetup(void);
|
||||
|
||||
void argvSetup(void)
|
||||
{
|
||||
Result rc=0;
|
||||
@ -136,6 +142,12 @@ void argvSetup(void)
|
||||
__system_argc++;
|
||||
}
|
||||
|
||||
|
||||
// Check for nxlink parameters
|
||||
nxlinkSetup();
|
||||
|
||||
__system_argv[__system_argc] = NULL;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -553,7 +553,7 @@ int ioctl(int fd, int request, ...) {
|
||||
if(flags == -1)
|
||||
return -1;
|
||||
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 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, ...) {
|
||||
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).
|
||||
@ -595,14 +621,30 @@ int fcntl(int fd, int cmd, ...) {
|
||||
*/
|
||||
if(cmd != F_GETFL && cmd != F_SETFL)
|
||||
return EOPNOTSUPP;
|
||||
|
||||
if (cmd == F_SETFL) {
|
||||
|
||||
va_start(args, cmd);
|
||||
flags = va_arg(args, int);
|
||||
va_end(args);
|
||||
|
||||
if (flags & ~ALL_FLAGS) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
flags = to_nx(flags);
|
||||
}
|
||||
|
||||
fd = _socketGetFd(fd);
|
||||
if(fd == -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) {
|
||||
@ -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) {
|
||||
int base;
|
||||
u32 val;
|
||||
@ -749,7 +791,7 @@ static int _socketInetAtonDetail(int *outBase, size_t *outNumBytes, const char *
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Adapted from ctrulib
|
||||
// Adapted from libctru
|
||||
static const char *inet_ntop4(const void *src, char *dst, socklen_t size) {
|
||||
const u8 *ip = src;
|
||||
|
||||
|
@ -2,97 +2,173 @@
|
||||
#include <malloc.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "kernel/rwlock.h"
|
||||
#include "services/fatal.h"
|
||||
#include "services/usb.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 UsbDsInterface* interface = NULL;
|
||||
static UsbDsEndpoint *g_usbComms_endpoint_in = NULL, *g_usbComms_endpoint_out = NULL;
|
||||
static usbCommsInterface g_usbCommsInterfaces[TOTAL_INTERFACES];
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
static void _usbCommsInterfaceExit(usbCommsInterface *interface)
|
||||
{
|
||||
rwlockWriteLock(&interface->lock);
|
||||
if (!interface->initialized) {
|
||||
rwlockWriteUnlock(&interface->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(ret)) {
|
||||
memset(g_usbComms_endpoint_in_buffer, 0, 0x1000);
|
||||
memset(g_usbComms_endpoint_out_buffer, 0, 0x1000);
|
||||
ret = _usbCommsInit();
|
||||
rwlockWriteLock(&interface->lock_in);
|
||||
rwlockWriteLock(&interface->lock_out);
|
||||
|
||||
if (ret != 0) {
|
||||
ret += 2000<<9;
|
||||
}
|
||||
interface->initialized = 0;
|
||||
|
||||
usbDsInterface_DisableInterface(interface->interface);
|
||||
usbDsEndpoint_Close(interface->endpoint_in);
|
||||
usbDsEndpoint_Close(interface->endpoint_out);
|
||||
usbDsInterface_Close(interface->interface);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void usbCommsExitEx(u32 interface)
|
||||
{
|
||||
u32 i;
|
||||
bool found=0;
|
||||
if (interface>=TOTAL_INTERFACES) return;
|
||||
|
||||
_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 (R_FAILED(ret)) {
|
||||
usbDsExit();
|
||||
|
||||
free(g_usbComms_endpoint_in_buffer);
|
||||
g_usbComms_endpoint_in_buffer = NULL;
|
||||
|
||||
free(g_usbComms_endpoint_out_buffer);
|
||||
g_usbComms_endpoint_out_buffer = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret += 1000<<9;
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(ret)) g_usbCommsInitialized=true;
|
||||
|
||||
return ret;
|
||||
if (!found) usbCommsExit();
|
||||
}
|
||||
|
||||
void usbCommsExit(void)
|
||||
{
|
||||
if (!g_usbCommsInitialized) return;
|
||||
u32 i;
|
||||
|
||||
rwlockWriteLock(&g_usbCommsLock);
|
||||
|
||||
usbDsExit();
|
||||
|
||||
g_usbCommsInitialized = false;
|
||||
|
||||
g_usbComms_endpoint_in = NULL;
|
||||
g_usbComms_endpoint_out = NULL;
|
||||
rwlockWriteUnlock(&g_usbCommsLock);
|
||||
|
||||
free(g_usbComms_endpoint_in_buffer);
|
||||
g_usbComms_endpoint_in_buffer = NULL;
|
||||
|
||||
free(g_usbComms_endpoint_out_buffer);
|
||||
g_usbComms_endpoint_out_buffer = NULL;
|
||||
for (i=0; i<TOTAL_INTERFACES; i++)
|
||||
{
|
||||
_usbCommsInterfaceExit(&g_usbCommsInterfaces[i]);
|
||||
}
|
||||
}
|
||||
|
||||
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 = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = USBDS_DEFAULT_InterfaceNumber,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.bInterfaceSubClass = USB_CLASS_VENDOR_SPEC,
|
||||
.bInterfaceProtocol = USB_CLASS_VENDOR_SPEC,
|
||||
.bInterfaceClass = bInterfaceClass,
|
||||
.bInterfaceSubClass = bInterfaceSubClass,
|
||||
.bInterfaceProtocol = bInterfaceProtocol,
|
||||
};
|
||||
|
||||
struct usb_endpoint_descriptor endpoint_descriptor_in = {
|
||||
@ -111,26 +187,44 @@ static Result _usbCommsInit(void)
|
||||
.wMaxPacketSize = 0x200,
|
||||
};
|
||||
|
||||
interface->initialized = 1;
|
||||
|
||||
//The buffer for PostBufferAsync commands must be 0x1000-byte aligned.
|
||||
interface->endpoint_in_buffer = memalign(0x1000, 0x1000);
|
||||
if (interface->endpoint_in_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
interface->endpoint_out_buffer = memalign(0x1000, 0x1000);
|
||||
if (interface->endpoint_out_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
||||
}
|
||||
|
||||
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.
|
||||
ret = usbDsGetDsInterface(&interface, &interface_descriptor, "usb");
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsGetDsInterface(&interface->interface, &interface_descriptor, "usb");
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
//Setup endpoints.
|
||||
ret = usbDsInterface_GetDsEndpoint(interface, &g_usbComms_endpoint_in, &endpoint_descriptor_in);//device->host
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsInterface_GetDsEndpoint(interface->interface, &interface->endpoint_in, &endpoint_descriptor_in);//device->host
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
ret = usbDsInterface_GetDsEndpoint(interface, &g_usbComms_endpoint_out, &endpoint_descriptor_out);//host->device
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsInterface_GetDsEndpoint(interface->interface, &interface->endpoint_out, &endpoint_descriptor_out);//host->device
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
ret = usbDsInterface_EnableInterface(interface);
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsInterface_EnableInterface(interface->interface);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
return ret;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize)
|
||||
static Result _usbCommsRead(usbCommsInterface *interface, void* buffer, size_t size, size_t *transferredSize)
|
||||
{
|
||||
Result ret=0;
|
||||
Result rc=0;
|
||||
u32 urbId=0;
|
||||
u8 *bufptr = (u8*)buffer;
|
||||
u8 *transfer_buffer = NULL;
|
||||
@ -141,15 +235,15 @@ static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize)
|
||||
usbDsReportData reportdata;
|
||||
|
||||
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
|
||||
ret = usbDsWaitReady();
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsWaitReady();
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
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.
|
||||
{
|
||||
transfer_buffer = g_usbComms_endpoint_out_buffer;
|
||||
memset(g_usbComms_endpoint_out_buffer, 0, 0x1000);
|
||||
transfer_buffer = interface->endpoint_out_buffer;
|
||||
memset(interface->endpoint_out_buffer, 0, 0x1000);
|
||||
|
||||
chunksize = 0x1000;
|
||||
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.
|
||||
ret = usbDsEndpoint_PostBufferAsync(g_usbComms_endpoint_out, transfer_buffer, chunksize, &urbId);
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_out, transfer_buffer, chunksize, &urbId);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
//Wait for the transfer to finish.
|
||||
svcWaitSynchronizationSingle(g_usbComms_endpoint_out->CompletionEvent, U64_MAX);
|
||||
svcClearEvent(g_usbComms_endpoint_out->CompletionEvent);
|
||||
svcWaitSynchronizationSingle(interface->endpoint_out->CompletionEvent, U64_MAX);
|
||||
svcClearEvent(interface->endpoint_out->CompletionEvent);
|
||||
|
||||
ret = usbDsEndpoint_GetReportData(g_usbComms_endpoint_out, &reportdata);
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsEndpoint_GetReportData(interface->endpoint_out, &reportdata);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
ret = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
|
||||
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;
|
||||
|
||||
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 chunksize=0;
|
||||
u8 *bufptr = (u8*)buffer;
|
||||
@ -206,21 +300,21 @@ static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferre
|
||||
usbDsReportData reportdata;
|
||||
|
||||
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
|
||||
ret = usbDsWaitReady();
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsWaitReady();
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
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.
|
||||
{
|
||||
transfer_buffer = g_usbComms_endpoint_in_buffer;
|
||||
memset(g_usbComms_endpoint_in_buffer, 0, 0x1000);
|
||||
transfer_buffer = interface->endpoint_in_buffer;
|
||||
memset(interface->endpoint_in_buffer, 0, 0x1000);
|
||||
|
||||
chunksize = 0x1000;
|
||||
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;
|
||||
|
||||
memcpy(g_usbComms_endpoint_in_buffer, bufptr, chunksize);
|
||||
memcpy(interface->endpoint_in_buffer, bufptr, chunksize);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -229,18 +323,18 @@ static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferre
|
||||
}
|
||||
|
||||
//Start a device->host transfer.
|
||||
ret = usbDsEndpoint_PostBufferAsync(g_usbComms_endpoint_in, transfer_buffer, chunksize, &urbId);
|
||||
if(R_FAILED(ret))return ret;
|
||||
rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_in, transfer_buffer, chunksize, &urbId);
|
||||
if(R_FAILED(rc))return rc;
|
||||
|
||||
//Wait for the transfer to finish.
|
||||
svcWaitSynchronizationSingle(g_usbComms_endpoint_in->CompletionEvent, U64_MAX);
|
||||
svcClearEvent(g_usbComms_endpoint_in->CompletionEvent);
|
||||
svcWaitSynchronizationSingle(interface->endpoint_in->CompletionEvent, U64_MAX);
|
||||
svcClearEvent(interface->endpoint_in->CompletionEvent);
|
||||
|
||||
ret = usbDsEndpoint_GetReportData(g_usbComms_endpoint_in, &reportdata);
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsEndpoint_GetReportData(interface->endpoint_in, &reportdata);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
ret = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
|
||||
if (R_FAILED(ret)) return ret;
|
||||
rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
return usbCommsReadEx(buffer, size, 0);
|
||||
}
|
||||
|
||||
size_t usbCommsWriteEx(const void* buffer, size_t size, u32 interface)
|
||||
{
|
||||
size_t transferredSize=0;
|
||||
u32 state=0;
|
||||
Result ret, ret2;
|
||||
ret = _usbCommsRead(buffer, size, &transferredSize);
|
||||
if (R_FAILED(ret)) {
|
||||
ret2 = usbDsGetState(&state);
|
||||
if (R_SUCCEEDED(ret2)) {
|
||||
if (state!=5) ret = _usbCommsRead(buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this.
|
||||
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_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;
|
||||
}
|
||||
|
||||
size_t usbCommsWrite(const void* buffer, size_t size)
|
||||
{
|
||||
size_t transferredSize=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;
|
||||
return usbCommsWriteEx(buffer, size, 0);
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ static u64 g_syscallHints[2];
|
||||
static Handle g_processHandle = INVALID_HANDLE;
|
||||
static char* g_nextLoadPath = NULL;
|
||||
static char* g_nextLoadArgv = NULL;
|
||||
static Result g_lastLoadResult = 0;
|
||||
|
||||
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];
|
||||
break;
|
||||
|
||||
case EntryType_LastLoadResult:
|
||||
g_lastLoadResult = ent->Value[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ent->Flags & EntryFlag_IsMandatory)
|
||||
{
|
||||
@ -164,3 +169,7 @@ Result envSetNextLoad(const char* path, const char* argv)
|
||||
bool envHasNextLoad(void) {
|
||||
return g_nextLoadPath != NULL;
|
||||
}
|
||||
|
||||
Result envGetLastLoadResult(void) {
|
||||
return g_lastLoadResult;
|
||||
}
|
||||
|
23
nx/source/runtime/nxlink.c
Normal file
23
nx/source/runtime/nxlink.c
Normal 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;
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "services/acc.h"
|
||||
@ -8,12 +10,17 @@ static u64 g_refCnt;
|
||||
|
||||
Result accountInitialize(void)
|
||||
{
|
||||
Result rc=0;
|
||||
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (serviceIsActive(&g_accSrv))
|
||||
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)
|
||||
@ -67,3 +74,153 @@ Result accountGetActiveUser(u128 *userID, bool *account_selected)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ Result fsMountSdcard(FsFileSystem* out) {
|
||||
rc = resp->result;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
save.titleID = titleID;
|
||||
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
|
||||
@ -207,7 +306,7 @@ Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags
|
||||
raw->size = size;
|
||||
raw->flags = flags;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -239,7 +338,7 @@ Result fsFsDeleteFile(FsFileSystem* fs, const char* path) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -271,7 +370,7 @@ Result fsFsCreateDirectory(FsFileSystem* fs, const char* path) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -303,7 +402,7 @@ Result fsFsDeleteDirectory(FsFileSystem* fs, const char* path) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 3;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -335,7 +434,7 @@ Result fsFsDeleteDirectoryRecursively(FsFileSystem* fs, const char* path) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -368,7 +467,7 @@ Result fsFsRenameFile(FsFileSystem* fs, const char* path0, const char* path1) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 5;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -401,7 +500,7 @@ Result fsFsRenameDirectory(FsFileSystem* fs, const char* path0, const char* path
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 6;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -433,7 +532,7 @@ Result fsFsGetEntryType(FsFileSystem* fs, const char* path, FsEntryType* out) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 7;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -472,7 +571,7 @@ Result fsFsOpenFile(FsFileSystem* fs, const char* path, int flags, FsFile* out)
|
||||
raw->cmd_id = 8;
|
||||
raw->flags = flags;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -486,7 +585,7 @@ Result fsFsOpenFile(FsFileSystem* fs, const char* path, int flags, FsFile* out)
|
||||
rc = resp->result;
|
||||
|
||||
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->flags = flags;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -524,7 +623,7 @@ Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, int flags, FsDir* o
|
||||
rc = resp->result;
|
||||
|
||||
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->cmd_id = 10;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -577,7 +676,7 @@ Result fsFsGetFreeSpace(FsFileSystem* fs, const char* path, u64* out) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 11;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -614,7 +713,7 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 12;
|
||||
|
||||
Result rc = ipcDispatch(fs->h);
|
||||
Result rc = serviceIpcDispatch(&fs->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -637,7 +736,7 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
|
||||
}
|
||||
|
||||
void fsFsClose(FsFileSystem* fs) {
|
||||
if(fs->h != INVALID_HANDLE) svcCloseHandle(fs->h);
|
||||
serviceClose(&fs->s);
|
||||
}
|
||||
|
||||
// IFile implementation
|
||||
@ -662,7 +761,7 @@ Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, size_t* out) {
|
||||
raw->offset = off;
|
||||
raw->read_size = len;
|
||||
|
||||
Result rc = ipcDispatch(f->h);
|
||||
Result rc = serviceIpcDispatch(&f->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -705,7 +804,7 @@ Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len) {
|
||||
raw->offset = off;
|
||||
raw->write_size = len;
|
||||
|
||||
Result rc = ipcDispatch(f->h);
|
||||
Result rc = serviceIpcDispatch(&f->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -736,7 +835,7 @@ Result fsFileFlush(FsFile* f) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
|
||||
Result rc = ipcDispatch(f->h);
|
||||
Result rc = serviceIpcDispatch(&f->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -769,7 +868,7 @@ Result fsFileSetSize(FsFile* f, u64 sz) {
|
||||
raw->cmd_id = 3;
|
||||
raw->size = sz;
|
||||
|
||||
Result rc = ipcDispatch(f->h);
|
||||
Result rc = serviceIpcDispatch(&f->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -800,7 +899,7 @@ Result fsFileGetSize(FsFile* f, u64* out) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
|
||||
Result rc = ipcDispatch(f->h);
|
||||
Result rc = serviceIpcDispatch(&f->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -820,12 +919,12 @@ Result fsFileGetSize(FsFile* f, u64* out) {
|
||||
}
|
||||
|
||||
void fsFileClose(FsFile* f) {
|
||||
if(f->h != INVALID_HANDLE) svcCloseHandle(f->h);
|
||||
serviceClose(&f->s);
|
||||
}
|
||||
|
||||
// IDirectory implementation
|
||||
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) {
|
||||
@ -845,7 +944,7 @@ Result fsDirRead(FsDir* d, u64 inval, size_t* total_entries, size_t max_entries,
|
||||
raw->cmd_id = 0;
|
||||
raw->inval = inval;
|
||||
|
||||
Result rc = ipcDispatch(d->h);
|
||||
Result rc = serviceIpcDispatch(&d->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -881,7 +980,7 @@ Result fsDirGetEntryCount(FsDir* d, u64* count) {
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
|
||||
Result rc = ipcDispatch(d->h);
|
||||
Result rc = serviceIpcDispatch(&d->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -920,7 +1019,7 @@ Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len) {
|
||||
raw->offset = off;
|
||||
raw->read_size = len;
|
||||
|
||||
Result rc = ipcDispatch(s->h);
|
||||
Result rc = serviceIpcDispatch(&s->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
@ -938,6 +1037,48 @@ Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len) {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -375,6 +375,10 @@ void hidJoystickRead(JoystickPosition *pos, HidControllerID id, HidControllerJoy
|
||||
}
|
||||
}
|
||||
|
||||
bool hidGetHandheldMode(void) {
|
||||
return g_controllerP1AutoID == CONTROLLER_HANDHELD;
|
||||
}
|
||||
|
||||
static Result _hidSetDualModeAll(void) {
|
||||
Result rc;
|
||||
int i;
|
||||
@ -731,26 +735,87 @@ Result hidIsVibrationPermitted(bool *flag) {
|
||||
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;
|
||||
Service srv;
|
||||
u32 tmp_type = type & 0xff;
|
||||
u32 tmp_id = id;
|
||||
size_t i;
|
||||
|
||||
if (total_handles == 0 || total_handles > 2)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
|
||||
if (tmp_type < 5) {
|
||||
if (tmp_type == 4) tmp_type |= 0x010000;
|
||||
tmp_type+= 3;
|
||||
if (tmp_id == CONTROLLER_HANDHELD)
|
||||
tmp_id = 0x20;
|
||||
|
||||
if (tmp_type & LAYOUT_PROCONTROLLER) {
|
||||
tmp_type = 3;
|
||||
}
|
||||
else {
|
||||
if (tmp_type == 5) tmp_type = 0x20;
|
||||
if (tmp_type == 6) tmp_type = 0x21;
|
||||
else if (tmp_type & TYPE_HANDHELD) {
|
||||
tmp_type = 4;
|
||||
}
|
||||
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 | (id & 0xff)<<8;
|
||||
VibrationDeviceHandles[0] = tmp_type | (tmp_id & 0xff)<<8;
|
||||
|
||||
if (total_handles > 1) {
|
||||
tmp_type &= 0xff;
|
||||
|
@ -6,12 +6,12 @@
|
||||
#include "services/pm.h"
|
||||
#include "services/sm.h"
|
||||
|
||||
static Service g_pmdmntSrv;
|
||||
static u64 g_refCnt;
|
||||
static Service g_pmdmntSrv, g_pmshellSrv;
|
||||
static u64 g_pmdmntRefCnt, g_pmshellRefCnt;
|
||||
|
||||
Result pmdmntInitialize(void)
|
||||
{
|
||||
atomicIncrement64(&g_refCnt);
|
||||
atomicIncrement64(&g_pmdmntRefCnt);
|
||||
|
||||
if (serviceIsActive(&g_pmdmntSrv))
|
||||
return 0;
|
||||
@ -21,11 +21,28 @@ Result pmdmntInitialize(void)
|
||||
|
||||
void pmdmntExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_refCnt) == 0) {
|
||||
if (atomicDecrement64(&g_pmdmntRefCnt) == 0) {
|
||||
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) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
@ -204,3 +221,43 @@ Result pmdmntEnableDebugForApplication(Handle* handle_out) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ endif
|
||||
include $(DEVKITPRO)/devkitA64/base_rules
|
||||
|
||||
PORTLIBS := $(PORTLIBS_PATH)/switch
|
||||
PATH := $(PORTLIBS)/bin:$(PATH)
|
||||
|
||||
LIBNX ?= $(DEVKITPRO)/libnx
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user