Merge remote-tracking branch 'refs/remotes/smealum/master'
This commit is contained in:
commit
46a7ba3b8f
@ -30,6 +30,7 @@ SOURCES := source \
|
||||
source/ndsp \
|
||||
source/services \
|
||||
source/services/soc \
|
||||
source/applets \
|
||||
source/util/rbtree \
|
||||
source/util/utf \
|
||||
source/system
|
||||
|
@ -14,6 +14,7 @@ extern "C" {
|
||||
#include <3ds/ipc.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/srv.h>
|
||||
#include <3ds/errf.h>
|
||||
#include <3ds/os.h>
|
||||
#include <3ds/synchronization.h>
|
||||
#include <3ds/thread.h>
|
||||
@ -28,6 +29,7 @@ extern "C" {
|
||||
|
||||
#include <3ds/services/ac.h>
|
||||
#include <3ds/services/am.h>
|
||||
#include <3ds/services/ampxi.h>
|
||||
#include <3ds/services/apt.h>
|
||||
#include <3ds/services/cam.h>
|
||||
#include <3ds/services/cfgnor.h>
|
||||
@ -49,6 +51,7 @@ extern "C" {
|
||||
#include <3ds/services/ps.h>
|
||||
#include <3ds/services/ptmu.h>
|
||||
#include <3ds/services/ptmsysm.h>
|
||||
#include <3ds/services/pxidev.h>
|
||||
#include <3ds/services/soc.h>
|
||||
#include <3ds/services/mic.h>
|
||||
#include <3ds/services/mvd.h>
|
||||
@ -59,17 +62,16 @@ extern "C" {
|
||||
#include <3ds/services/y2r.h>
|
||||
#include <3ds/services/hb.h>
|
||||
|
||||
#include <3ds/services/ampxi.h>
|
||||
|
||||
#include <3ds/gpu/gx.h>
|
||||
#include <3ds/gpu/gpu.h>
|
||||
#include <3ds/gpu/gpu-old.h>
|
||||
#include <3ds/gpu/shbin.h>
|
||||
#include <3ds/gpu/shaderProgram.h>
|
||||
|
||||
#include <3ds/ndsp/ndsp.h>
|
||||
#include <3ds/ndsp/channel.h>
|
||||
|
||||
#include <3ds/applets/swkbd.h>
|
||||
|
||||
#include <3ds/sdmc.h>
|
||||
#include <3ds/romfs.h>
|
||||
#include <3ds/font.h>
|
||||
@ -104,4 +106,4 @@ extern "C" {
|
||||
* @example threads/event/source/main.c
|
||||
* @example time/rtc/source/main.c
|
||||
*/
|
||||
|
||||
|
||||
|
320
libctru/include/3ds/applets/swkbd.h
Normal file
320
libctru/include/3ds/applets/swkbd.h
Normal file
@ -0,0 +1,320 @@
|
||||
/**
|
||||
* @file swkbd.h
|
||||
* @brief Software keyboard applet.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/// Keyboard types.
|
||||
typedef enum
|
||||
{
|
||||
SWKBD_TYPE_NORMAL = 0, ///< Normal keyboard with several pages (QWERTY/accents/symbol/mobile)
|
||||
SWKBD_TYPE_QWERTY, ///< QWERTY keyboard only.
|
||||
SWKBD_TYPE_NUMPAD, ///< Number pad.
|
||||
SWKBD_TYPE_WESTERN, ///< On JPN systems, a text keyboard without Japanese input capabilities, otherwise same as SWKBD_TYPE_NORMAL.
|
||||
} SwkbdType;
|
||||
|
||||
/// Accepted input types.
|
||||
typedef enum
|
||||
{
|
||||
SWKBD_ANYTHING = 0, ///< All inputs are accepted.
|
||||
SWKBD_NOTEMPTY, ///< Empty inputs are not accepted.
|
||||
SWKBD_NOTEMPTY_NOTBLANK, ///< Empty or blank inputs (consisting solely of whitespace) are not accepted.
|
||||
SWKBD_NOTBLANK_NOTEMPTY = SWKBD_NOTEMPTY_NOTBLANK,
|
||||
SWKBD_NOTBLANK, ///< Blank inputs (consisting solely of whitespace) are not accepted, but empty inputs are.
|
||||
SWKBD_FIXEDLEN, ///< The input must have a fixed length (specified by maxTextLength in swkbdInit).
|
||||
} SwkbdValidInput;
|
||||
|
||||
/// Keyboard dialog buttons.
|
||||
typedef enum
|
||||
{
|
||||
SWKBD_BUTTON_LEFT = 0, ///< Left button (usually Cancel)
|
||||
SWKBD_BUTTON_MIDDLE, ///< Middle button (usually I Forgot)
|
||||
SWKBD_BUTTON_RIGHT, ///< Right button (usually OK)
|
||||
SWKBD_BUTTON_CONFIRM = SWKBD_BUTTON_RIGHT,
|
||||
SWKBD_BUTTON_NONE, ///< No button (returned by swkbdInputText in special cases)
|
||||
} SwkbdButton;
|
||||
|
||||
/// Keyboard password modes.
|
||||
typedef enum
|
||||
{
|
||||
SWKBD_PASSWORD_NONE = 0, ///< Characters are not concealed.
|
||||
SWKBD_PASSWORD_HIDE, ///< Characters are concealed immediately.
|
||||
SWKBD_PASSWORD_HIDE_DELAY, ///< Characters are concealed a second after they've been typed.
|
||||
} SwkbdPasswordMode;
|
||||
|
||||
/// Keyboard input filtering flags.
|
||||
enum
|
||||
{
|
||||
SWKBD_FILTER_DIGITS = BIT(0), ///< Disallow the use of more than a certain number of digits (0 or more)
|
||||
SWKBD_FILTER_AT = BIT(1), ///< Disallow the use of the @ sign.
|
||||
SWKBD_FILTER_PERCENT = BIT(2), ///< Disallow the use of the % sign.
|
||||
SWKBD_FILTER_BACKSLASH = BIT(3), ///< Disallow the use of the \ sign.
|
||||
SWKBD_FILTER_PROFANITY = BIT(4), ///< Disallow profanity using Nintendo's profanity filter.
|
||||
SWKBD_FILTER_CALLBACK = BIT(5), ///< Use a callback in order to check the input.
|
||||
};
|
||||
|
||||
/// Keyboard features.
|
||||
enum
|
||||
{
|
||||
SWKBD_PARENTAL = BIT(0), ///< Parental PIN mode.
|
||||
SWKBD_DARKEN_TOP_SCREEN = BIT(1), ///< Darken the top screen when the keyboard is shown.
|
||||
SWKBD_PREDICTIVE_INPUT = BIT(2), ///< Enable predictive input (necessary for Kanji input in JPN systems).
|
||||
SWKBD_MULTILINE = BIT(3), ///< Enable multiline input.
|
||||
SWKBD_FIXED_WIDTH = BIT(4), ///< Enable fixed-width mode.
|
||||
SWKBD_ALLOW_HOME = BIT(5), ///< Allow the usage of the HOME button.
|
||||
SWKBD_ALLOW_RESET = BIT(6), ///< Allow the usage of a software-reset combination.
|
||||
SWKBD_ALLOW_POWER = BIT(7), ///< Allow the usage of the POWER button.
|
||||
SWKBD_DEFAULT_QWERTY = BIT(9), ///< Default to the QWERTY page when the keyboard is shown.
|
||||
};
|
||||
|
||||
/// Keyboard filter callback return values.
|
||||
typedef enum
|
||||
{
|
||||
SWKBD_CALLBACK_OK = 0, ///< Specifies that the input is valid.
|
||||
SWKBD_CALLBACK_CLOSE, ///< Displays an error message, then closes the keyboard.
|
||||
SWKBD_CALLBACK_CONTINUE, ///< Displays an error message and continues displaying the keyboard.
|
||||
} SwkbdCallbackResult;
|
||||
|
||||
/// Keyboard return values.
|
||||
typedef enum
|
||||
{
|
||||
SWKBD_NONE = -1, ///< Dummy/unused.
|
||||
SWKBD_INVALID_INPUT = -2, ///< Invalid parameters to swkbd.
|
||||
SWKBD_OUTOFMEM = -3, ///< Out of memory.
|
||||
|
||||
SWKBD_D0_CLICK = 0, ///< The button was clicked in 1-button dialogs.
|
||||
SWKBD_D1_CLICK0, ///< The left button was clicked in 2-button dialogs.
|
||||
SWKBD_D1_CLICK1, ///< The right button was clicked in 2-button dialogs.
|
||||
SWKBD_D2_CLICK0, ///< The left button was clicked in 3-button dialogs.
|
||||
SWKBD_D2_CLICK1, ///< The middle button was clicked in 3-button dialogs.
|
||||
SWKBD_D2_CLICK2, ///< The right button was clicked in 3-button dialogs.
|
||||
|
||||
SWKBD_HOMEPRESSED = 10, ///< The HOME button was pressed.
|
||||
SWKBD_RESETPRESSED, ///< The soft-reset key combination was pressed.
|
||||
SWKBD_POWERPRESSED, ///< The POWER button was pressed.
|
||||
|
||||
SWKBD_PARENTAL_OK = 20, ///< The parental PIN was verified successfully.
|
||||
SWKBD_PARENTAL_FAIL, ///< The parental PIN was incorrect.
|
||||
|
||||
SWKBD_BANNED_INPUT = 30, ///< The filter callback returned SWKBD_CALLBACK_CLOSE.
|
||||
} SwkbdResult;
|
||||
|
||||
/// Maximum dictionary word length, in UTF-16 code units.
|
||||
#define SWKBD_MAX_WORD_LEN 40
|
||||
/// Maximum button text length, in UTF-16 code units.
|
||||
#define SWKBD_MAX_BUTTON_TEXT_LEN 16
|
||||
/// Maximum hint text length, in UTF-16 code units.
|
||||
#define SWKBD_MAX_HINT_TEXT_LEN 64
|
||||
/// Maximum filter callback error message length, in UTF-16 code units.
|
||||
#define SWKBD_MAX_CALLBACK_MSG_LEN 256
|
||||
|
||||
/// Keyboard dictionary word for predictive input.
|
||||
typedef struct
|
||||
{
|
||||
u16 reading[SWKBD_MAX_WORD_LEN+1]; ///< Reading of the word (that is, the string that needs to be typed).
|
||||
u16 word[SWKBD_MAX_WORD_LEN+1]; ///< Spelling of the word.
|
||||
u8 language; ///< Language the word applies to.
|
||||
bool all_languages; ///< Specifies if the word applies to all languages.
|
||||
} SwkbdDictWord;
|
||||
|
||||
/// Keyboard filter callback function.
|
||||
typedef SwkbdCallbackResult (* SwkbdCallbackFn)(void* user, const char** ppMessage, const char* text, size_t textlen);
|
||||
/// Keyboard status data.
|
||||
typedef struct { u32 data[0x11]; } SwkbdStatusData;
|
||||
/// Keyboard predictive input learning data.
|
||||
typedef struct { u32 data[0x291B]; } SwkbdLearningData;
|
||||
|
||||
/// Internal libctru book-keeping structure for software keyboards.
|
||||
typedef struct
|
||||
{
|
||||
const char* initial_text;
|
||||
const SwkbdDictWord* dict;
|
||||
SwkbdStatusData* status_data;
|
||||
SwkbdLearningData* learning_data;
|
||||
SwkbdCallbackFn callback;
|
||||
void* callback_user;
|
||||
} SwkbdExtra;
|
||||
|
||||
/// Software keyboard parameter structure, it shouldn't be modified directly.
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
int num_buttons_m1;
|
||||
int valid_input;
|
||||
int password_mode;
|
||||
int is_parental_screen;
|
||||
int darken_top_screen;
|
||||
u32 filter_flags;
|
||||
u32 save_state_flags;
|
||||
u16 max_text_len;
|
||||
u16 dict_word_count;
|
||||
u16 max_digits;
|
||||
u16 button_text[3][SWKBD_MAX_BUTTON_TEXT_LEN+1];
|
||||
u16 numpad_keys[2];
|
||||
u16 hint_text[SWKBD_MAX_HINT_TEXT_LEN+1];
|
||||
bool predictive_input;
|
||||
bool multiline;
|
||||
bool fixed_width;
|
||||
bool allow_home;
|
||||
bool allow_reset;
|
||||
bool allow_power;
|
||||
bool unknown; // XX: what is this supposed to do? "communicateWithOtherRegions"
|
||||
bool default_qwerty;
|
||||
bool button_submits_text[4];
|
||||
u16 language; // XX: not working? supposedly 0 = use system language, CFG_Language+1 = pick language
|
||||
int initial_text_offset;
|
||||
int dict_offset;
|
||||
int initial_status_offset;
|
||||
int initial_learning_offset;
|
||||
size_t shared_memory_size;
|
||||
u32 version;
|
||||
SwkbdResult result;
|
||||
int status_offset;
|
||||
int learning_offset;
|
||||
int text_offset;
|
||||
u16 text_length;
|
||||
int callback_result;
|
||||
u16 callback_msg[SWKBD_MAX_CALLBACK_MSG_LEN+1];
|
||||
bool skip_at_check;
|
||||
union
|
||||
{
|
||||
u8 reserved[171];
|
||||
SwkbdExtra extra;
|
||||
};
|
||||
} SwkbdState;
|
||||
|
||||
/**
|
||||
* @brief Initializes software keyboard status.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param type Keyboard type.
|
||||
* @param numButtons Number of dialog buttons to display (1, 2 or 3).
|
||||
* @param maxTextLength Maximum number of UTF-16 code units that input text can have (or -1 to let libctru use a big default).
|
||||
*/
|
||||
void swkbdInit(SwkbdState* swkbd, SwkbdType type, int numButtons, int maxTextLength);
|
||||
|
||||
/**
|
||||
* @brief Configures password mode in a software keyboard.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param mode Password mode.
|
||||
*/
|
||||
static inline void swkbdSetPasswordMode(SwkbdState* swkbd, SwkbdPasswordMode mode)
|
||||
{
|
||||
swkbd->password_mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures input validation in a software keyboard.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param validInput Specifies which inputs are valid.
|
||||
* @param filterFlags Bitmask specifying which characters are disallowed (filtered).
|
||||
* @param maxDigits In case digits are disallowed, specifies how many digits are allowed at maximum in input strings (0 completely restricts digit input).
|
||||
*/
|
||||
static inline void swkbdSetValidation(SwkbdState* swkbd, SwkbdValidInput validInput, u32 filterFlags, int maxDigits)
|
||||
{
|
||||
swkbd->valid_input = validInput;
|
||||
swkbd->filter_flags = filterFlags;
|
||||
swkbd->max_digits = (filterFlags & SWKBD_FILTER_DIGITS) ? maxDigits : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures what characters will the two bottom keys in a numpad produce.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param left Unicode codepoint produced by the leftmost key in the bottom row (0 hides the key).
|
||||
* @param left Unicode codepoint produced by the rightmost key in the bottom row (0 hides the key).
|
||||
*/
|
||||
static inline void swkbdSetNumpadKeys(SwkbdState* swkbd, int left, int right)
|
||||
{
|
||||
swkbd->numpad_keys[0] = left;
|
||||
swkbd->numpad_keys[1] = right;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Specifies which special features are enabled in a software keyboard.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param features Feature bitmask.
|
||||
*/
|
||||
void swkbdSetFeatures(SwkbdState* swkbd, u32 features);
|
||||
|
||||
/**
|
||||
* @brief Sets the hint text of a software keyboard (that is, the help text that is displayed when the textbox is empty).
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param text Hint text.
|
||||
*/
|
||||
void swkbdSetHintText(SwkbdState* swkbd, const char* text);
|
||||
|
||||
/**
|
||||
* @brief Configures a dialog button in a software keyboard.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param button Specifies which button to configure.
|
||||
* @param text Button text.
|
||||
* @param submit Specifies whether pushing the button will submit the text or discard it.
|
||||
*/
|
||||
void swkbdSetButton(SwkbdState* swkbd, SwkbdButton button, const char* text, bool submit);
|
||||
|
||||
/**
|
||||
* @brief Sets the initial text that a software keyboard will display on launch.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param text Initial text.
|
||||
*/
|
||||
void swkbdSetInitialText(SwkbdState* swkbd, const char* text);
|
||||
|
||||
/**
|
||||
* @brief Configures a word in a predictive dictionary for use with a software keyboard.
|
||||
* @param word Pointer to dictionary word structure.
|
||||
* @param reading Reading of the word, that is, the sequence of characters that need to be typed to trigger the word in the predictive input system.
|
||||
* @param text Spelling of the word, that is, the actual characters that will be produced when the user decides to select the word.
|
||||
*/
|
||||
void swkbdSetDictWord(SwkbdDictWord* word, const char* reading, const char* text);
|
||||
|
||||
/**
|
||||
* @brief Sets the custom word dictionary to be used with the predictive input system of a software keyboard.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param dict Pointer to dictionary words.
|
||||
* @param wordCount Number of words in the dictionary.
|
||||
*/
|
||||
void swkbdSetDictionary(SwkbdState* swkbd, const SwkbdDictWord* dict, int wordCount);
|
||||
|
||||
/**
|
||||
* @brief Configures software keyboard internal status management.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param data Pointer to internal status structure (can be in, out or both depending on the other parameters).
|
||||
* @param in Specifies whether the data should be read from the structure when the keyboard is launched.
|
||||
* @param out Specifies whether the data should be written to the structure when the keyboard is closed.
|
||||
*/
|
||||
void swkbdSetStatusData(SwkbdState* swkbd, SwkbdStatusData* data, bool in, bool out);
|
||||
|
||||
/**
|
||||
* @brief Configures software keyboard predictive input learning data management.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param data Pointer to learning data structure (can be in, out or both depending on the other parameters).
|
||||
* @param in Specifies whether the data should be read from the structure when the keyboard is launched.
|
||||
* @param out Specifies whether the data should be written to the structure when the keyboard is closed.
|
||||
*/
|
||||
void swkbdSetLearningData(SwkbdState* swkbd, SwkbdLearningData* data, bool in, bool out);
|
||||
|
||||
/**
|
||||
* @brief Configures a custom function to be used to check the validity of input when it is submitted in a software keyboard.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param callback Filter callback function.
|
||||
* @param user Custom data to be passed to the callback function.
|
||||
*/
|
||||
void swkbdSetFilterCallback(SwkbdState* swkbd, SwkbdCallbackFn callback, void* user);
|
||||
|
||||
/**
|
||||
* @brief Launches a software keyboard in order to input text.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @param buf Pointer to output buffer which will hold the inputted text.
|
||||
* @param bufsize Maximum number of UTF-8 code units that the buffer can hold (including null terminator).
|
||||
* @return The identifier of the dialog button that was pressed, or SWKBD_BUTTON_NONE if a different condition was triggered - in that case use swkbdGetResult to check the condition.
|
||||
*/
|
||||
SwkbdButton swkbdInputText(SwkbdState* swkbd, char* buf, size_t bufsize);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the result condition of a software keyboard after it has been used.
|
||||
* @param swkbd Pointer to swkbd state.
|
||||
* @return The result value.
|
||||
*/
|
||||
static inline SwkbdResult swkbdGetResult(SwkbdState* swkbd)
|
||||
{
|
||||
return swkbd->result;
|
||||
}
|
118
libctru/include/3ds/errf.h
Normal file
118
libctru/include/3ds/errf.h
Normal file
@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file errf.h
|
||||
* @brief Error Display API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <3ds/types.h>
|
||||
|
||||
/// Used for register dumps.
|
||||
typedef struct {
|
||||
u32 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, cpsr;
|
||||
} ERRF_ExceptionContext;
|
||||
|
||||
/// Types of errors that can be thrown by err:f.
|
||||
typedef enum {
|
||||
ERRF_ERRTYPE_GENERIC = 0, ///< For generic errors. Shows miscellaneous info.
|
||||
ERRF_ERRTYPE_MEM_CORRUPT = 1, ///< Same output as generic, but informs the user that "the System Memory has been damaged".
|
||||
ERRF_ERRTYPE_CARD_REMOVED = 2, ///< Displays the "The Game Card was removed." message.
|
||||
ERRF_ERRTYPE_EXCEPTION = 3, ///< For exceptions, or more specifically 'crashes'. union data should be exception_data.
|
||||
ERRF_ERRTYPE_FAILURE = 4, ///< For general failure. Shows a message. union data should have a string set in failure_mesg
|
||||
ERRF_ERRTYPE_LOGGED = 5 ///< Outputs logs to NAND in some cases.
|
||||
} ERRF_ErrType;
|
||||
|
||||
/// Types of 'Exceptions' thrown for ERRF_ERRTYPE_EXCEPTION
|
||||
typedef enum {
|
||||
ERRF_EXCEPTION_PREFETCH_ABORT = 0, ///< Prefetch Abort
|
||||
ERRF_EXCEPTION_DATA_ABORT = 1, ///< Data abort
|
||||
ERRF_EXCEPTION_UNDEFINED = 2, ///< Undefined instruction
|
||||
ERRF_EXCEPTION_VFP = 3 ///< VFP (floating point) exception.
|
||||
} ERRF_ExceptionType;
|
||||
|
||||
typedef struct {
|
||||
ERRF_ExceptionType type; ///< Type of the exception. One of the ERRF_EXCEPTION_* values.
|
||||
u8 reserved[3];
|
||||
u32 reg1; ///< If type is prefetch, this should be ifsr, and on data abort dfsr
|
||||
u32 reg2; ///< If type is prefetch, this should be r15, and dfar on data abort
|
||||
u32 fpexc;
|
||||
u32 fpinst;
|
||||
u32 fpint2;
|
||||
} ERRF_ExceptionInfo;
|
||||
|
||||
typedef struct {
|
||||
ERRF_ExceptionInfo excep; ///< Exception info struct
|
||||
ERRF_ExceptionContext regs; ///< Register dump.
|
||||
u8 pad[4];
|
||||
} ERRF_ExceptionData;
|
||||
|
||||
typedef struct {
|
||||
ERRF_ErrType type; ///< Type, one of the ERRF_ERRTYPE_* enum
|
||||
u8 revHigh; ///< High revison ID
|
||||
u16 revLow; ///< Low revision ID
|
||||
u32 resCode; ///< Result code
|
||||
u32 pcAddr; ///< PC address at exception
|
||||
u32 procId; ///< Process ID.
|
||||
u64 titleId; ///< Title ID.
|
||||
u64 appTitleId; ///< Application Title ID.
|
||||
union {
|
||||
ERRF_ExceptionData exception_data; ///< Data for when type is ERRF_ERRTYPE_EXCEPTION
|
||||
char failure_mesg[60]; ///< String for when type is ERRF_ERRTYPE_FAILURE
|
||||
} data; ///< The different types of data for errors.
|
||||
} ERRF_FatalErrInfo;
|
||||
|
||||
/// Initializes ERR:f. Unless you plan to call ERRF_Throw yourself, do not use this.
|
||||
Result errfInit(void);
|
||||
|
||||
/// Exits ERR:f. Unless you plan to call ERRF_Throw yourself, do not use this.
|
||||
void errfExit(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the current err:f API session handle.
|
||||
* @return The current err:f API session handle.
|
||||
*/
|
||||
Handle *errfGetSessionHandle(void);
|
||||
|
||||
/**
|
||||
* @brief Throws a system error and possibly results in ErrDisp triggering.
|
||||
* @param[in] error Error to throw.
|
||||
*
|
||||
* After performing this, the system may panic and need to be rebooted. Extra information will be displayed on the
|
||||
* top screen with a developer console or the proper patches in a CFW applied.
|
||||
*
|
||||
* The error may not be shown and execution aborted until errfExit(void) is called.
|
||||
*
|
||||
* You may wish to use ERRF_ThrowResult() or ERRF_ThrowResultWithMessage() instead of
|
||||
* constructing the ERRF_FatalErrInfo struct yourself.
|
||||
*/
|
||||
Result ERRF_Throw(const ERRF_FatalErrInfo* error);
|
||||
|
||||
/**
|
||||
* @brief Throws a system error with the given Result code.
|
||||
* @param[in] failure Result code to throw.
|
||||
*
|
||||
* This calls ERRF_Throw() with error type ERRF_ERRTYPE_GENERIC and fills in the required data.
|
||||
*
|
||||
* This function \em does fill in the address where this function was called from.
|
||||
*
|
||||
* See https://3dbrew.org/wiki/ERR:Throw#Generic for expected top screen output
|
||||
* on development units/patched ErrDisp.
|
||||
*/
|
||||
Result ERRF_ThrowResult(Result failure);
|
||||
|
||||
/**
|
||||
* @brief Throws a system error with the given Result code and message.
|
||||
* @param[in] failure Result code to throw.
|
||||
* @param[in] message The message to display.
|
||||
*
|
||||
* This calls ERRF_Throw() with error type ERRF_ERRTYPE_FAILURE and fills in the required data.
|
||||
*
|
||||
* This function does \em not fill in the address where this function was called from because it
|
||||
* would not be displayed.
|
||||
*
|
||||
* The message is only displayed on development units/patched ErrDisp.
|
||||
*
|
||||
* See https://3dbrew.org/wiki/ERR:Throw#Result_Failure for expected top screen output
|
||||
* on development units/patched ErrDisp.
|
||||
*/
|
||||
Result ERRF_ThrowResultWithMessage(Result failure, const char* message);
|
@ -1,235 +0,0 @@
|
||||
/**
|
||||
* @file gpu-old.h
|
||||
* @brief Deprecated GPU functions which should not be used in new code.
|
||||
* @description These functions have been superseeded by direct GPU register writes, or external GPU libraries.
|
||||
* @deprecated
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "gpu.h"
|
||||
|
||||
/**
|
||||
* @brief Initializes the GPU.
|
||||
* @param gsphandle GSP handle to use.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_Init(Handle *gsphandle) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Resets the GPU.
|
||||
* @param gxbuf GX command buffer to use.
|
||||
* @param gpuBuf GPU command buffer to use.
|
||||
* @param gpuBufSize GPU command buffer size.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_Reset(u32* gxbuf, u32* gpuBuf, u32 gpuBufSize) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets a shader float uniform.
|
||||
* @param type Type of shader to set the uniform of.
|
||||
* @param startreg Start of the uniform register to set.
|
||||
* @param data Data to set.
|
||||
* @param numreg Number of registers to set.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetFloatUniform(GPU_SHADER_TYPE type, u32 startreg, u32* data, u32 numreg) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the viewport.
|
||||
* @param depthBuffer Buffer to output depth data to.
|
||||
* @param colorBuffer Buffer to output color data to.
|
||||
* @param x X of the viewport.
|
||||
* @param y Y of the viewport.
|
||||
* @param w Width of the viewport.
|
||||
* @param h Height of the viewport.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetViewport(u32* depthBuffer, u32* colorBuffer, u32 x, u32 y, u32 w, u32 h) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the current scissor test mode.
|
||||
* @param mode Scissor test mode to use.
|
||||
* @param x X of the scissor region.
|
||||
* @param y Y of the scissor region.
|
||||
* @param w Width of the scissor region.
|
||||
* @param h Height of the scissor region.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetScissorTest(GPU_SCISSORMODE mode, u32 left, u32 bottom, u32 right, u32 top) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the depth map.
|
||||
* @param zScale Z scale to use.
|
||||
* @param zOffset Z offset to use.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_DepthMap(float zScale, float zOffset) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the alpha test parameters.
|
||||
* @param enable Whether to enable alpha testing.
|
||||
* @param function Test function to use.
|
||||
* @param ref Reference value to use.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetAlphaTest(bool enable, GPU_TESTFUNC function, u8 ref) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the depth test parameters and pixel write mask.
|
||||
* @note GPU_WRITEMASK values can be ORed together.
|
||||
* @param enable Whether to enable depth testing.
|
||||
* @param function Test function to use.
|
||||
* @param writemask Pixel write mask to use.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetDepthTestAndWriteMask(bool enable, GPU_TESTFUNC function, GPU_WRITEMASK writemask) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the stencil test parameters.
|
||||
* @param enable Whether to enable stencil testing.
|
||||
* @param function Test function to use.
|
||||
* @param ref Reference value to use.
|
||||
* @param input_mask Input mask to use.
|
||||
* @param write_mask Write mask to use.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref, u8 input_mask, u8 write_mask) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the stencil test operators.
|
||||
* @param sfail Operator to use on source test failure.
|
||||
* @param dfail Operator to use on destination test failure.
|
||||
* @param pass Operator to use on test passing.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetStencilOp(GPU_STENCILOP sfail, GPU_STENCILOP dfail, GPU_STENCILOP pass) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the face culling mode.
|
||||
* @param mode Face culling mode to use.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetFaceCulling(GPU_CULLMODE mode) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the combiner buffer write parameters.
|
||||
* @note Use GPU_TEV_BUFFER_WRITE_CONFIG to build the parameters.
|
||||
* @note Only the first four TEV stages can write to the combiner buffer.
|
||||
* @param rgb_config RGB configuration to use.
|
||||
* @param alpha_config Alpha configuration to use.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetCombinerBufferWrite(u8 rgb_config, u8 alpha_config) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the alpha blending parameters.
|
||||
* @note Cannot be used with GPU_SetColorLogicOp.
|
||||
* @param colorEquation Blend equation to use for color components.
|
||||
* @param alphaEquation Blend equation to use for the alpha component.
|
||||
* @param colorSrc Source factor of color components.
|
||||
* @param colorDst Destination factor of color components.
|
||||
* @param alphaSrc Source factor of the alpha component.
|
||||
* @param alphaDst Destination factor of the alpha component.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetAlphaBlending(GPU_BLENDEQUATION colorEquation, GPU_BLENDEQUATION alphaEquation,
|
||||
GPU_BLENDFACTOR colorSrc, GPU_BLENDFACTOR colorDst,
|
||||
GPU_BLENDFACTOR alphaSrc, GPU_BLENDFACTOR alphaDst) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the color logic operator.
|
||||
* @note Cannot be used with GPU_SetAlphaBlending.
|
||||
* @param op Operator to set.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetColorLogicOp(GPU_LOGICOP op) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the blending color.
|
||||
* @param r Red component.
|
||||
* @param g Green component.
|
||||
* @param b Blue component.
|
||||
* @param a Alpha component.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetBlendingColor(u8 r, u8 g, u8 b, u8 a) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the VBO attribute buffers.
|
||||
* @param totalAttributes Total number of attributes.
|
||||
* @param baseAddress Base address of the VBO.
|
||||
* @param attributeFormats Attribute format data.
|
||||
* @param attributeMask Attribute mask.
|
||||
* @param attributePermutation Attribute permutations.
|
||||
* @param numBuffers Number of buffers.
|
||||
* @param bufferOffsets Offsets of the buffers.
|
||||
* @param bufferPermutations Buffer permutations.
|
||||
* @param bufferNumAttributes Numbers of attributes of the buffers.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetAttributeBuffers(u8 totalAttributes, u32* baseAddress, u64 attributeFormats, u16 attributeMask, u64 attributePermutation, u8 numBuffers, u32 bufferOffsets[], u64 bufferPermutations[], u8 bufferNumAttributes[]) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the enabled texture units.
|
||||
* @param units Units to enable. OR texture unit values together to create this value.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetTextureEnable(GPU_TEXUNIT units) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the texture data of a texture unit.
|
||||
* @param unit Texture unit to use.
|
||||
* @param data Data to load. Must be in linear memory or VRAM.
|
||||
* @param width Width of the texture.
|
||||
* @param height Height of the texture.
|
||||
* @param Parameters of the texture, such as filters and wrap modes.
|
||||
* @param colorType Color type of the texture.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetTexture(GPU_TEXUNIT unit, u32* data, u16 width, u16 height, u32 param, GPU_TEXCOLOR colorType) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the border color of a texture unit.
|
||||
* @param unit Texture unit to use.
|
||||
* @param borderColor The color used for the border when using the @ref GPU_CLAMP_TO_BORDER wrap mode.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetTextureBorderColor(GPU_TEXUNIT unit,u32 borderColor) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Sets the parameters of a texture combiner.
|
||||
* @param id ID of the combiner.
|
||||
* @param rgbSources RGB source configuration.
|
||||
* @param alphaSources Alpha source configuration.
|
||||
* @param rgbOperands RGB operand configuration.
|
||||
* @param alphaOperands Alpha operand configuration.
|
||||
* @param rgbCombine RGB combiner function.
|
||||
* @param alphaCombine Alpha combiner function.
|
||||
* @param constantColor Constant color to provide.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_SetTexEnv(u8 id, u16 rgbSources, u16 alphaSources, u16 rgbOperands, u16 alphaOperands, GPU_COMBINEFUNC rgbCombine, GPU_COMBINEFUNC alphaCombine, u32 constantColor) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Draws an array of vertex data.
|
||||
* @param primitive Primitive to draw.
|
||||
* @param first First vertex to draw.
|
||||
* @param count Number of vertices to draw.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_DrawArray(GPU_Primitive_t primitive, u32 first, u32 count) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Draws vertex elements.
|
||||
* @param primitive Primitive to draw.
|
||||
* @param indexArray Array of vertex indices to use.
|
||||
* @param n Number of vertices to draw.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n) DEPRECATED;
|
||||
|
||||
/**
|
||||
* @brief Finishes drawing.
|
||||
* @deprecated
|
||||
*/
|
||||
void GPU_FinishDrawing() DEPRECATED;
|
@ -41,7 +41,7 @@ void GPUCMD_GetBuffer(u32** adr, u32* size, u32* offset);
|
||||
* @param cmd Buffer containing commands to add.
|
||||
* @param size Size of the buffer.
|
||||
*/
|
||||
void GPUCMD_AddRawCommands(u32* cmd, u32 size);
|
||||
void GPUCMD_AddRawCommands(const u32* cmd, u32 size);
|
||||
|
||||
/// Executes the GPU command buffer.
|
||||
void GPUCMD_Run(void);
|
||||
@ -55,7 +55,7 @@ void GPUCMD_FlushAndRun(void);
|
||||
* @param param Parameters of the command.
|
||||
* @param paramlength Size of the parameter buffer.
|
||||
*/
|
||||
void GPUCMD_Add(u32 header, u32* param, u32 paramlength);
|
||||
void GPUCMD_Add(u32 header, const u32* param, u32 paramlength);
|
||||
|
||||
/// Finalizes the GPU command buffer.
|
||||
void GPUCMD_Finalize(void);
|
||||
|
@ -33,18 +33,8 @@ typedef struct
|
||||
shaderInstance_s* geometryShader; ///< Geometry shader.
|
||||
u32 geoShaderInputPermutation[2]; ///< Geometry shader input permutation.
|
||||
u8 geoShaderInputStride; ///< Geometry shader input stride.
|
||||
u8 geoShaderMode; ///< Geometry shader operation mode.
|
||||
}shaderProgram_s;
|
||||
|
||||
/// Geometry shader operation modes.
|
||||
typedef enum
|
||||
{
|
||||
GSH_NORMAL = 0, ///< Normal operation.
|
||||
GSH_PARTICLE = 1, ///< Particle system.
|
||||
GSH_SUBDIVISION_LOOP = 2, ///< Loop subdivision surface.
|
||||
GSH_SUBDIVISION_CATMULL_CLARK = 3, ///< Catmull-Clark subdivision surface.
|
||||
} geoShaderMode;
|
||||
|
||||
/**
|
||||
* @brief Initializes a shader instance.
|
||||
* @param si Shader instance to initialize.
|
||||
@ -104,7 +94,7 @@ Result shaderProgramSetVsh(shaderProgram_s* sp, DVLE_s* dvle);
|
||||
* @brief Sets the geometry shader of a shader program.
|
||||
* @param sp Shader program to use.
|
||||
* @param dvle Geometry shader to set.
|
||||
* @param stride Stride of the geometry shader.
|
||||
* @param stride Input stride of the shader (pass 0 to match the number of outputs of the vertex shader).
|
||||
*/
|
||||
Result shaderProgramSetGsh(shaderProgram_s* sp, DVLE_s* dvle, u8 stride);
|
||||
|
||||
@ -115,13 +105,6 @@ Result shaderProgramSetGsh(shaderProgram_s* sp, DVLE_s* dvle, u8 stride);
|
||||
*/
|
||||
Result shaderProgramSetGshInputPermutation(shaderProgram_s* sp, u64 permutation);
|
||||
|
||||
/**
|
||||
* @brief Configures the operation mode of the geometry shader of a shader program.
|
||||
* @param sp Shader program to use.
|
||||
* @param mode Operation mode to use.
|
||||
*/
|
||||
Result shaderProgramSetGshMode(shaderProgram_s* sp, geoShaderMode mode);
|
||||
|
||||
/**
|
||||
* @brief Configures the shader units to use the specified shader program.
|
||||
* @param sp Shader program to use.
|
||||
|
@ -28,9 +28,18 @@ typedef enum{
|
||||
RESULT_TEXCOORD0W = 0x4, ///< Texture coordinate 0 W.
|
||||
RESULT_TEXCOORD1 = 0x5, ///< Texture coordinate 1.
|
||||
RESULT_TEXCOORD2 = 0x6, ///< Texture coordinate 2.
|
||||
RESULT_VIEW = 0x8 ///< View.
|
||||
RESULT_VIEW = 0x8, ///< View.
|
||||
RESULT_DUMMY = 0x9, ///< Dummy attribute (used as passthrough for geometry shader input).
|
||||
}DVLE_outputAttribute_t;
|
||||
|
||||
/// Geometry shader operation modes.
|
||||
typedef enum
|
||||
{
|
||||
GSH_POINT = 0, ///< Point processing mode.
|
||||
GSH_VARIABLE_PRIM = 1, ///< Variable-size primitive processing mode.
|
||||
GSH_FIXED_PRIM = 2, ///< Fixed-size primitive processing mode.
|
||||
} DVLE_geoShaderMode;
|
||||
|
||||
/// DVLP data.
|
||||
typedef struct{
|
||||
u32 codeSize; ///< Code size.
|
||||
@ -64,6 +73,11 @@ typedef struct{
|
||||
/// DVLE data.
|
||||
typedef struct{
|
||||
DVLE_type type; ///< DVLE type.
|
||||
bool mergeOutmaps; ///< true = merge vertex/geometry shader outmaps ('dummy' output attribute is present).
|
||||
DVLE_geoShaderMode gshMode; ///< Geometry shader operation mode.
|
||||
u8 gshFixedVtxStart; ///< Starting float uniform register number for storing the fixed-size primitive vertex array.
|
||||
u8 gshVariableVtxNum; ///< Number of fully-defined vertices in the variable-size primitive vertex array.
|
||||
u8 gshFixedVtxNum; ///< Number of vertices in the fixed-size primitive vertex array.
|
||||
DVLP_s* dvlp; ///< Contained DVLPs.
|
||||
u32 mainOffset; ///< Offset of the start of the main function.
|
||||
u32 endmainOffset; ///< Offset of the end of the main function.
|
||||
|
@ -161,7 +161,6 @@ void osSetSpeedupEnable(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Gets the NAND system-version stored in NVer/CVer.
|
||||
* The romfs device must not be already initialized(via romfsInit*()) at the time this function is called, since this code uses the romfs device.
|
||||
* @param nver_versionbin Output OS_VersionBin structure for the data read from NVer.
|
||||
* @param cver_versionbin Output OS_VersionBin structure for the data read from CVer.
|
||||
* @return The result-code. This value can be positive if opening "romfs:/version.bin" fails with stdio, since errno would be returned in that case. In some cases the error can be special negative values as well.
|
||||
|
@ -45,15 +45,36 @@ typedef struct
|
||||
u16 name[]; ///< Name. (UTF-16)
|
||||
} romfs_file;
|
||||
|
||||
/// Initializes the RomFS driver.
|
||||
Result romfsInit(void);
|
||||
struct romfs_mount;
|
||||
|
||||
/**
|
||||
* @brief Initializes the RomFS driver from a RomFS file.
|
||||
* @brief Mounts the Application's RomFS.
|
||||
* @param mount Output mount handle
|
||||
*/
|
||||
Result romfsMount(struct romfs_mount **mount);
|
||||
static inline Result romfsInit(void)
|
||||
{
|
||||
return romfsMount(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mounts RomFS from an open file.
|
||||
* @param file Handle of the RomFS file.
|
||||
* @param offset Offset of the RomFS within the file.
|
||||
* @param mount Output mount handle
|
||||
*/
|
||||
Result romfsInitFromFile(Handle file, u32 offset);
|
||||
Result romfsMountFromFile(Handle file, u32 offset, struct romfs_mount **mount);
|
||||
static inline Result romfsInitFromFile(Handle file, u32 offset)
|
||||
{
|
||||
return romfsMountFromFile(file, offset, NULL);
|
||||
}
|
||||
|
||||
/// Exits the RomFS driver.
|
||||
Result romfsExit(void);
|
||||
/// Bind the RomFS mount
|
||||
Result romfsBind(struct romfs_mount *mount);
|
||||
|
||||
/// Unmounts the RomFS device.
|
||||
Result romfsUnmount(struct romfs_mount *mount);
|
||||
static inline Result romfsExit(void)
|
||||
{
|
||||
return romfsUnmount(NULL);
|
||||
}
|
||||
|
@ -56,9 +56,12 @@ typedef struct {
|
||||
u64 titlesFreeSpace; ///< Free space for titles.
|
||||
} AM_TWLPartitionInfo;
|
||||
|
||||
/// Initializes AM.
|
||||
/// Initializes AM. This doesn't initialize with "am:app", see amAppInit().
|
||||
Result amInit(void);
|
||||
|
||||
/// Initializes AM with a service which has access to the amapp-commands. This should only be used when using the amapp commands, not non-amapp AM commands.
|
||||
Result amAppInit(void);
|
||||
|
||||
/// Exits AM.
|
||||
void amExit(void);
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
* Retrieved from http://3dbrew.org/wiki/NS_and_APT_Services#AppIDs
|
||||
*/
|
||||
typedef enum {
|
||||
APPID_NONE = 0,
|
||||
APPID_HOMEMENU = 0x101, ///< Home Menu
|
||||
APPID_CAMERA = 0x110, ///< Camera applet
|
||||
APPID_FRIENDS_LIST = 0x112, ///< Friends List applet
|
||||
@ -32,34 +33,82 @@ typedef enum {
|
||||
APPID_MEMOLIB = 0x409, ///< memolib
|
||||
} NS_APPID;
|
||||
|
||||
/// App status values.
|
||||
/// APT applet position.
|
||||
typedef enum {
|
||||
APP_NOTINITIALIZED, ///< App not initialized.
|
||||
APP_RUNNING, ///< App running.
|
||||
APP_SUSPENDED, ///< App suspended.
|
||||
APP_EXITING, ///< App exiting.
|
||||
APP_SUSPENDING, ///< App suspending.
|
||||
APP_SLEEPMODE, ///< App in sleep mode.
|
||||
APP_PREPARE_SLEEPMODE, ///< App preparing to enter sleep mode.
|
||||
APP_APPLETSTARTED, ///< Applet started.
|
||||
APP_APPLETCLOSED ///< Applet closed.
|
||||
} APT_AppStatus;
|
||||
APTPOS_NONE = -1, ///< No position specified.
|
||||
APTPOS_APP = 0, ///< Application.
|
||||
APTPOS_APPLIB = 1, ///< Application library (?).
|
||||
APTPOS_SYS = 2, ///< System applet.
|
||||
APTPOS_SYSLIB = 3, ///< System library (?).
|
||||
APTPOS_RESIDENT = 4, ///< Resident applet.
|
||||
} APT_AppletPos;
|
||||
|
||||
typedef u8 APT_AppletAttr;
|
||||
|
||||
/// Create an APT_AppletAttr bitfield from its components.
|
||||
static inline APT_AppletAttr aptMakeAppletAttr(APT_AppletPos pos, bool manualGpuRights, bool manualDspRights)
|
||||
{
|
||||
return (pos&7) | (manualGpuRights ? BIT(3) : 0) | (manualDspRights ? BIT(4) : 0);
|
||||
}
|
||||
|
||||
/// APT query reply.
|
||||
typedef enum {
|
||||
APTREPLY_REJECT = 0,
|
||||
APTREPLY_ACCEPT = 1,
|
||||
APTREPLY_LATER = 2,
|
||||
} APT_QueryReply;
|
||||
|
||||
/// APT signals.
|
||||
typedef enum {
|
||||
APTSIGNAL_HOMEBUTTON = 1, ///< Home button pressed.
|
||||
// 2: sleep-mode related?
|
||||
APTSIGNAL_PREPARESLEEP = 3, ///< Prepare to enter sleep mode.
|
||||
// 4: triggered when ptm:s GetShellStatus() returns 5.
|
||||
APTSIGNAL_ENTERSLEEP = 5, ///< Enter sleep mode.
|
||||
APTSIGNAL_WAKEUP = 6, ///< Wake from sleep mode.
|
||||
APTSIGNAL_ENABLE = 7, ///< Enable.
|
||||
APTSIGNAL_POWERBUTTON = 8, ///< Power button pressed.
|
||||
APTSIGNAL_UTILITY = 9, ///< Utility called.
|
||||
APTSIGNAL_SLEEPSYSTEM = 10, ///< System sleeping.
|
||||
APTSIGNAL_ERROR = 11 ///< Error occurred.
|
||||
APTSIGNAL_NONE = 0, ///< No signal received.
|
||||
APTSIGNAL_HOMEBUTTON = 1, ///< HOME button pressed.
|
||||
APTSIGNAL_HOMEBUTTON2 = 2, ///< HOME button pressed (again?).
|
||||
APTSIGNAL_SLEEP_QUERY = 3, ///< Prepare to enter sleep mode.
|
||||
APTSIGNAL_SLEEP_CANCEL = 4, ///< Triggered when ptm:s GetShellStatus() returns 5.
|
||||
APTSIGNAL_SLEEP_ENTER = 5, ///< Enter sleep mode.
|
||||
APTSIGNAL_SLEEP_WAKEUP = 6, ///< Wake from sleep mode.
|
||||
APTSIGNAL_SHUTDOWN = 7, ///< Shutdown.
|
||||
APTSIGNAL_POWERBUTTON = 8, ///< POWER button pressed.
|
||||
APTSIGNAL_POWERBUTTON2 = 9, ///< POWER button cleared (?).
|
||||
APTSIGNAL_TRY_SLEEP = 10, ///< System sleeping (?).
|
||||
APTSIGNAL_ORDERTOCLOSE = 11, ///< Order to close (such as when an error happens?).
|
||||
} APT_Signal;
|
||||
|
||||
/// APT commands.
|
||||
typedef enum {
|
||||
APTCMD_NONE = 0, ///< No command received.
|
||||
APTCMD_WAKEUP = 1, ///< Applet should wake up.
|
||||
APTCMD_REQUEST = 2, ///< Source applet sent us a parameter.
|
||||
APTCMD_RESPONSE = 3, ///< Target applet replied to our parameter.
|
||||
APTCMD_EXIT = 4, ///< Exit (??)
|
||||
APTCMD_MESSAGE = 5, ///< Message (??)
|
||||
APTCMD_HOMEBUTTON_ONCE = 6, ///< HOME button pressed once.
|
||||
APTCMD_HOMEBUTTON_TWICE = 7, ///< HOME button pressed twice (double-pressed).
|
||||
APTCMD_DSP_SLEEP = 8, ///< DSP should sleep (manual DSP rights related?).
|
||||
APTCMD_DSP_WAKEUP = 9, ///< DSP should wake up (manual DSP rights related?).
|
||||
APTCMD_WAKEUP_EXIT = 10, ///< Applet wakes up due to a different applet exiting.
|
||||
APTCMD_WAKEUP_PAUSE = 11, ///< Applet wakes up after being paused through HOME menu.
|
||||
APTCMD_WAKEUP_CANCEL = 12, ///< Applet wakes up due to being cancelled.
|
||||
APTCMD_WAKEUP_CANCELALL = 13, ///< Applet wakes up due to all applets being cancelled.
|
||||
APTCMD_WAKEUP_POWERBUTTON = 14, ///< Applet wakes up due to POWER button being pressed (?).
|
||||
APTCMD_WAKEUP_JUMPTOHOME = 15, ///< Applet wakes up and is instructed to jump to HOME menu (?).
|
||||
APTCMD_SYSAPPLET_REQUEST = 16, ///< Request for sysapplet (?).
|
||||
APTCMD_WAKEUP_LAUNCHAPP = 17, ///< Applet wakes up and is instructed to launch another applet (?).
|
||||
} APT_Command;
|
||||
|
||||
/// APT capture buffer information.
|
||||
typedef struct
|
||||
{
|
||||
u32 size;
|
||||
u32 is3D;
|
||||
struct
|
||||
{
|
||||
u32 leftOffset;
|
||||
u32 rightOffset;
|
||||
u32 format;
|
||||
} top, bottom;
|
||||
} aptCaptureBufInfo;
|
||||
|
||||
/// APT hook types.
|
||||
typedef enum {
|
||||
APTHOOK_ONSUSPEND = 0, ///< App suspended.
|
||||
@ -82,8 +131,8 @@ typedef struct tag_aptHookCookie
|
||||
void* param; ///< Callback parameter.
|
||||
} aptHookCookie;
|
||||
|
||||
/// APT events.
|
||||
extern Handle aptEvents[3];
|
||||
/// APT message callback.
|
||||
typedef void (*aptMessageCb)(void* user, NS_APPID sender, void* msg, size_t msgsize);
|
||||
|
||||
/// Initializes APT.
|
||||
Result aptInit(void);
|
||||
@ -91,55 +140,17 @@ Result aptInit(void);
|
||||
/// Exits APT.
|
||||
void aptExit(void);
|
||||
|
||||
/// Opens an APT session.
|
||||
void aptOpenSession(void);
|
||||
|
||||
/// Closes an APT session.
|
||||
void aptCloseSession(void);
|
||||
|
||||
/**
|
||||
* @brief Sets the app's status.
|
||||
* @param status Status to set.
|
||||
* @brief Sends an APT command through IPC, taking care of locking, opening and closing an APT session.
|
||||
* @param aptcmdbuf Pointer to command buffer (should have capacity for at least 16 words).
|
||||
*/
|
||||
void aptSetStatus(APT_AppStatus status);
|
||||
|
||||
/**
|
||||
* @brief Gets the app's status.
|
||||
* @return The app's status.
|
||||
*/
|
||||
APT_AppStatus aptGetStatus(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the app's power status.
|
||||
* When the status is APT_SUSPEND, this can be used to check what triggered a return-to-menu.
|
||||
* @return The app's power status. (0 = normal, 1 = power button pressed)
|
||||
*/
|
||||
u32 aptGetStatusPower(void);
|
||||
|
||||
/**
|
||||
* @brief Sets the app's power status.
|
||||
* @param status Power status to set.
|
||||
*/
|
||||
void aptSetStatusPower(u32 status);
|
||||
|
||||
/**
|
||||
* @brief Triggers a return to the home menu.
|
||||
*
|
||||
* This should be called by the user application when aptGetStatus() returns APP_SUSPENDING, not calling this will result in return-to-menu being disabled with the status left at APP_SUSPENDING. This function will not return until the system returns to the application, or when the status was changed to APP_EXITING.
|
||||
*/
|
||||
void aptReturnToMenu(void);
|
||||
|
||||
/// Waits for an APT status event.
|
||||
void aptWaitStatusEvent(void);
|
||||
|
||||
/// Signals that the app is ready to sleep.
|
||||
void aptSignalReadyForSleep(void);
|
||||
Result aptSendCommand(u32* aptcmdbuf);
|
||||
|
||||
/**
|
||||
* @brief Gets whether to allow the system to enter sleep mode.
|
||||
* @return Whether sleep mode is allowed.
|
||||
*/
|
||||
bool aptIsSleepAllowed();
|
||||
bool aptIsSleepAllowed(void);
|
||||
|
||||
/**
|
||||
* @brief Sets whether to allow the system to enter sleep mode.
|
||||
@ -147,15 +158,9 @@ bool aptIsSleepAllowed();
|
||||
*/
|
||||
void aptSetSleepAllowed(bool allowed);
|
||||
|
||||
/**
|
||||
* @brief Gets the menu's app ID.
|
||||
* @return The menu's app ID.
|
||||
*/
|
||||
NS_APPID aptGetMenuAppID(void);
|
||||
|
||||
/**
|
||||
* @brief Processes the current APT status. Generally used within a main loop.
|
||||
* @return Whether the application is closing.
|
||||
* @return Whether the application should continue running.
|
||||
*/
|
||||
bool aptMainLoop(void);
|
||||
|
||||
@ -173,6 +178,23 @@ void aptHook(aptHookCookie* cookie, aptHookFn callback, void* param);
|
||||
*/
|
||||
void aptUnhook(aptHookCookie* cookie);
|
||||
|
||||
/**
|
||||
* @brief Sets the function to be called when an APT message from another applet is received.
|
||||
* @param callback Callback function.
|
||||
* @param user User-defined data to be passed to the callback.
|
||||
*/
|
||||
void aptSetMessageCallback(aptMessageCb callback, void* user);
|
||||
|
||||
/**
|
||||
* @brief Launches a library applet.
|
||||
* @param appId ID of the applet to launch.
|
||||
* @param buf Input/output buffer that contains launch parameters on entry and result data on exit.
|
||||
* @param bufsize Size of the buffer.
|
||||
* @param handle Handle to pass to the library applet.
|
||||
* @return Whether the application should continue running after the library applet launch.
|
||||
*/
|
||||
bool aptLaunchLibraryApplet(NS_APPID appId, void* buf, size_t bufsize, Handle handle);
|
||||
|
||||
/**
|
||||
* @brief Gets an APT lock handle.
|
||||
* @param flags Flags to use.
|
||||
@ -183,10 +205,11 @@ Result APT_GetLockHandle(u16 flags, Handle* lockHandle);
|
||||
/**
|
||||
* @brief Initializes an application's registration with APT.
|
||||
* @param appId ID of the application.
|
||||
* @param eventHandle1 Pointer to output the signal event handle to.
|
||||
* @param eventHandle2 Pointer to output the launch and exit event handle to.
|
||||
* @param attr Attributes of the application.
|
||||
* @param signalEvent Pointer to output the signal event handle to.
|
||||
* @param resumeEvent Pointer to output the resume event handle to.
|
||||
*/
|
||||
Result APT_Initialize(NS_APPID appId, Handle* eventHandle1, Handle* eventHandle2);
|
||||
Result APT_Initialize(NS_APPID appId, APT_AppletAttr attr, Handle* signalEvent, Handle* resumeEvent);
|
||||
|
||||
/**
|
||||
* @brief Terminates an application's registration with APT.
|
||||
@ -199,31 +222,41 @@ Result APT_HardwareResetAsync(void);
|
||||
|
||||
/**
|
||||
* @brief Enables APT.
|
||||
* @param a Parameter to enable with.
|
||||
* @param attr Attributes of the application.
|
||||
*/
|
||||
Result APT_Enable(u32 a);
|
||||
Result APT_Enable(APT_AppletAttr attr);
|
||||
|
||||
/**
|
||||
* @brief Gets applet management info.
|
||||
* @param inval Requested applet type.
|
||||
* @param outval8 Pointer to output the current applet type to.
|
||||
* @param outval32 Pointer to output the requested app ID to.
|
||||
* @param menu_appid Pointer to output the home menu app ID to.
|
||||
* @param active_appid Pointer to output the currently active app ID to.
|
||||
* @param pAttributes Pointer to output the atrributes to.
|
||||
* @param inpos Requested applet position.
|
||||
* @param outpos Pointer to output the position of the current applet to.
|
||||
* @param req_appid Pointer to output the AppID of the applet at the requested position to.
|
||||
* @param menu_appid Pointer to output the HOME menu AppID to.
|
||||
* @param active_appid Pointer to output the AppID of the currently active applet to.
|
||||
*/
|
||||
Result APT_GetAppletManInfo(u8 inval, u8 *outval8, u32 *outval32, NS_APPID *menu_appid, NS_APPID *active_appid);
|
||||
Result APT_GetAppletManInfo(APT_AppletPos inpos, APT_AppletPos* outpos, NS_APPID* req_appid, NS_APPID* menu_appid, NS_APPID* active_appid);
|
||||
|
||||
/**
|
||||
* @brief Gets the menu's app ID.
|
||||
* @return The menu's app ID.
|
||||
*/
|
||||
static inline NS_APPID aptGetMenuAppID(void)
|
||||
{
|
||||
NS_APPID menu_appid = APPID_NONE;
|
||||
APT_GetAppletManInfo(APTPOS_NONE, NULL, NULL, &menu_appid, NULL);
|
||||
return menu_appid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets an applet's information.
|
||||
* @param appID ID of the applet.
|
||||
* @param appID AppID of the applet.
|
||||
* @param pProgramID Pointer to output the program ID to.
|
||||
* @param pMediaType Pointer to output the media type to.
|
||||
* @param pRegistered Pointer to output the registration status to.
|
||||
* @param pLoadState Pointer to output the load state to.
|
||||
* @param pAttributes Pointer to output the atrributes to.
|
||||
* @param pAttributes Pointer to output the applet atrributes to.
|
||||
*/
|
||||
Result APT_GetAppletInfo(NS_APPID appID, u64* pProgramID, u8* pMediaType, u8* pRegistered, u8* pLoadState, u32* pAttributes);
|
||||
Result APT_GetAppletInfo(NS_APPID appID, u64* pProgramID, u8* pMediaType, bool* pRegistered, bool* pLoadState, APT_AppletAttr* pAttributes);
|
||||
|
||||
/**
|
||||
* @brief Gets an applet's program information.
|
||||
@ -256,13 +289,13 @@ Result APT_PrepareToJumpToHomeMenu(void);
|
||||
* @param Size of the parameter buffer.
|
||||
* @param handle Handle to pass.
|
||||
*/
|
||||
Result APT_JumpToHomeMenu(const u8 *param, size_t paramSize, Handle handle);
|
||||
Result APT_JumpToHomeMenu(const void* param, size_t paramSize, Handle handle);
|
||||
|
||||
/**
|
||||
* @brief Prepares to jump to an application.
|
||||
* @param a Application to jump to.
|
||||
* @param exiting Specifies whether the applet is exiting.
|
||||
*/
|
||||
Result APT_PrepareToJumpToApplication(u32 a);
|
||||
Result APT_PrepareToJumpToApplication(bool exiting);
|
||||
|
||||
/**
|
||||
* @brief Jumps to an application.
|
||||
@ -270,14 +303,14 @@ Result APT_PrepareToJumpToApplication(u32 a);
|
||||
* @param Size of the parameter buffer.
|
||||
* @param handle Handle to pass.
|
||||
*/
|
||||
Result APT_JumpToApplication(const u8 *param, size_t paramSize, Handle handle);
|
||||
Result APT_JumpToApplication(const void* param, size_t paramSize, Handle handle);
|
||||
|
||||
/**
|
||||
* @brief Gets whether an application is registered.
|
||||
* @param appID ID of the application.
|
||||
* @param out Pointer to output the registration state to.
|
||||
*/
|
||||
Result APT_IsRegistered(NS_APPID appID, u8* out);
|
||||
Result APT_IsRegistered(NS_APPID appID, bool* out);
|
||||
|
||||
/**
|
||||
* @brief Inquires as to whether a signal has been received.
|
||||
@ -294,59 +327,85 @@ Result APT_NotifyToWait(NS_APPID appID);
|
||||
|
||||
/**
|
||||
* @brief Calls an applet utility function.
|
||||
* @param id Utility function to call.
|
||||
* @param out Pointer to write output data to.
|
||||
* @param a Utility function to call.
|
||||
* @param size1 Size of the first buffer.
|
||||
* @param buf1 First buffer.
|
||||
* @param size2 Size of the second buffer.
|
||||
* @param buf2 Second buffer.
|
||||
* @param outSize Size of the output buffer.
|
||||
* @param in Pointer to the input data.
|
||||
* @param inSize Size of the input buffer.
|
||||
*/
|
||||
Result APT_AppletUtility(u32* out, u32 a, u32 size1, u8* buf1, u32 size2, u8* buf2);
|
||||
Result APT_AppletUtility(int id, void* out, size_t outSize, const void* in, size_t inSize);
|
||||
|
||||
/// Sleeps if shell is closed (?).
|
||||
Result APT_SleepIfShellClosed(void);
|
||||
|
||||
/**
|
||||
* @brief Tries to lock a transition (?).
|
||||
* @param transition Transition ID.
|
||||
* @param succeeded Pointer to output whether the lock was successfully applied.
|
||||
*/
|
||||
Result APT_TryLockTransition(u32 transition, bool* succeeded);
|
||||
|
||||
/**
|
||||
* @brief Unlocks a transition (?).
|
||||
* @param transition Transition ID.
|
||||
*/
|
||||
Result APT_UnlockTransition(u32 transition);
|
||||
|
||||
/**
|
||||
* @brief Glances at a receieved parameter without removing it from the queue.
|
||||
* @param appID ID of the application.
|
||||
* @param bufferSize Size of the buffer.
|
||||
* @param appID AppID of the application.
|
||||
* @param buffer Buffer to receive to.
|
||||
* @param bufferSize Size of the buffer.
|
||||
* @param sender Pointer to output the sender's AppID to.
|
||||
* @param command Pointer to output the command ID to.
|
||||
* @param actualSize Pointer to output the actual received data size to.
|
||||
* @param signalType Pointer to output the signal type to.
|
||||
* @param parameter Pointer to output the parameter handle to.
|
||||
*/
|
||||
Result APT_GlanceParameter(NS_APPID appID, u32 bufferSize, u32* buffer, u32* actualSize, u8* signalType);
|
||||
Result APT_GlanceParameter(NS_APPID appID, void* buffer, size_t bufferSize, NS_APPID* sender, APT_Command* command, size_t* actualSize, Handle* parameter);
|
||||
|
||||
/**
|
||||
* @brief Receives a parameter.
|
||||
* @param appID ID of the application.
|
||||
* @param bufferSize Size of the buffer.
|
||||
* @param appID AppID of the application.
|
||||
* @param buffer Buffer to receive to.
|
||||
* @param bufferSize Size of the buffer.
|
||||
* @param sender Pointer to output the sender's AppID to.
|
||||
* @param command Pointer to output the command ID to.
|
||||
* @param actualSize Pointer to output the actual received data size to.
|
||||
* @param signalType Pointer to output the signal type to.
|
||||
* @param parameter Pointer to output the parameter handle to.
|
||||
*/
|
||||
Result APT_ReceiveParameter(NS_APPID appID, u32 bufferSize, u32* buffer, u32* actualSize, u8* signalType);
|
||||
Result APT_ReceiveParameter(NS_APPID appID, void* buffer, size_t bufferSize, NS_APPID* sender, APT_Command* command, size_t* actualSize, Handle* parameter);
|
||||
|
||||
/**
|
||||
* @brief Sends a parameter.
|
||||
* @param src_appID ID of the source application.
|
||||
* @param dst_appID ID of the destination application.
|
||||
* @param bufferSize Size of the buffer.
|
||||
* @param source AppID of the source application.
|
||||
* @param dest AppID of the destination application.
|
||||
* @param command Command to send.
|
||||
* @param buffer Buffer to send.
|
||||
* @param paramhandle Handle to pass.
|
||||
* @param signalType Signal type to send.
|
||||
* @param bufferSize Size of the buffer.
|
||||
* @param parameter Parameter handle to pass.
|
||||
*/
|
||||
Result APT_SendParameter(NS_APPID src_appID, NS_APPID dst_appID, u32 bufferSize, u32* buffer, Handle paramhandle, u8 signalType);
|
||||
Result APT_SendParameter(NS_APPID source, NS_APPID dest, APT_Command command, const void* buffer, u32 bufferSize, Handle parameter);
|
||||
|
||||
/**
|
||||
* @brief Cancels a parameter which matches the specified source and dest AppIDs.
|
||||
* @param source AppID of the source application (use APPID_NONE to disable the check).
|
||||
* @param dest AppID of the destination application (use APPID_NONE to disable the check).
|
||||
* @param success Pointer to output true if a parameter was cancelled, or false otherwise.
|
||||
*/
|
||||
Result APT_CancelParameter(NS_APPID source, NS_APPID dest, bool* success);
|
||||
|
||||
/**
|
||||
* @brief Sends capture buffer information.
|
||||
* @param bufferSize Size of the buffer to send.
|
||||
* @param buffer Buffer to send.
|
||||
* @param captureBuf Capture buffer information to send.
|
||||
*/
|
||||
Result APT_SendCaptureBufferInfo(u32 bufferSize, u32* buffer);
|
||||
Result APT_SendCaptureBufferInfo(const aptCaptureBufInfo* captureBuf);
|
||||
|
||||
/**
|
||||
* @brief Replies to a sleep query.
|
||||
* @param appID ID of the application.
|
||||
* @param a Parameter to reply with.
|
||||
* @param reply Query reply value.
|
||||
*/
|
||||
Result APT_ReplySleepQuery(NS_APPID appID, u32 a);
|
||||
Result APT_ReplySleepQuery(NS_APPID appID, APT_QueryReply reply);
|
||||
|
||||
/**
|
||||
* @brief Replies that a sleep notification has been completed.
|
||||
@ -356,9 +415,9 @@ Result APT_ReplySleepNotificationComplete(NS_APPID appID);
|
||||
|
||||
/**
|
||||
* @brief Prepares to close the application.
|
||||
* @param a Whether the jump is to the home menu.
|
||||
* @param cancelPreload Whether applet preloads should be cancelled.
|
||||
*/
|
||||
Result APT_PrepareToCloseApplication(u8 a);
|
||||
Result APT_PrepareToCloseApplication(bool cancelPreload);
|
||||
|
||||
/**
|
||||
* @brief Closes the application.
|
||||
@ -366,7 +425,7 @@ Result APT_PrepareToCloseApplication(u8 a);
|
||||
* @param paramSize Size of param.
|
||||
* @param handle Handle to pass.
|
||||
*/
|
||||
Result APT_CloseApplication(const u8 *param, size_t paramSize, Handle handle);
|
||||
Result APT_CloseApplication(const void* param, size_t paramSize, Handle handle);
|
||||
|
||||
/**
|
||||
* @brief Sets the application's CPU time limit.
|
||||
@ -382,22 +441,9 @@ Result APT_GetAppCpuTimeLimit(u32 *percent);
|
||||
|
||||
/**
|
||||
* @brief Checks whether the system is a New 3DS.
|
||||
* Note: this function is unreliable, see: http://3dbrew.org/wiki/APT:PrepareToStartApplication
|
||||
* @param out Pointer to write the New 3DS flag to.
|
||||
*/
|
||||
Result APT_CheckNew3DS_Application(u8 *out);
|
||||
|
||||
/**
|
||||
* @brief Checks whether the system is a New 3DS.
|
||||
* @param out Pointer to write the New 3DS flag to.
|
||||
*/
|
||||
Result APT_CheckNew3DS_System(u8 *out);
|
||||
|
||||
/**
|
||||
* @brief Checks whether the system is a New 3DS.
|
||||
* @param out Pointer to write the New 3DS flag to.
|
||||
*/
|
||||
Result APT_CheckNew3DS(u8 *out);
|
||||
Result APT_CheckNew3DS(bool* out);
|
||||
|
||||
/**
|
||||
* @brief Prepares for an applicaton jump.
|
||||
@ -405,56 +451,45 @@ Result APT_CheckNew3DS(u8 *out);
|
||||
* @param programID ID of the program to jump to.
|
||||
* @param mediatype Media type of the program to jump to.
|
||||
*/
|
||||
Result APT_PrepareToDoAppJump(u8 flags, u64 programID, u8 mediatype);
|
||||
Result APT_PrepareToDoApplicationJump(u8 flags, u64 programID, u8 mediatype);
|
||||
|
||||
/**
|
||||
* @brief Performs an application jump.
|
||||
* @param NSbuf0Size Size of NSbuf0Ptr.
|
||||
* @param NSbuf1Size Size of NSbuf1Ptr.
|
||||
* @param NSbuf0Ptr Launch buffer 0.
|
||||
* @param NSbuf1Ptr Launch buffer 1.
|
||||
* @param param Parameter buffer.
|
||||
* @param paramSize Size of parameter buffer.
|
||||
* @param hmac HMAC buffer (should be 0x20 bytes long).
|
||||
*/
|
||||
Result APT_DoAppJump(u32 NSbuf0Size, u32 NSbuf1Size, u8 *NSbuf0Ptr, u8 *NSbuf1Ptr);
|
||||
Result APT_DoApplicationJump(const void* param, size_t paramSize, const void* hmac);
|
||||
|
||||
/**
|
||||
* @brief Prepares to start a library applet.
|
||||
* @param appID ID of the applet to start.
|
||||
* @param appID AppID of the applet to start.
|
||||
*/
|
||||
Result APT_PrepareToStartLibraryApplet(NS_APPID appID);
|
||||
|
||||
/**
|
||||
* @brief Starts a library applet.
|
||||
* @param appID ID of the applet to launch.
|
||||
* @param inhandle Handle to pass to the applet.
|
||||
* @param parambuf Buffer containing applet parameters.
|
||||
* @param parambufsize Size of parambuf.
|
||||
* @param appID AppID of the applet to launch.
|
||||
* @param param Buffer containing applet parameters.
|
||||
* @param paramsize Size of the buffer.
|
||||
* @param handle Handle to pass to the applet.
|
||||
*/
|
||||
Result APT_StartLibraryApplet(NS_APPID appID, Handle inhandle, u32 *parambuf, u32 parambufsize);
|
||||
|
||||
/**
|
||||
* @brief Launches a library applet.
|
||||
* Note: This is not usable from the homebrew launcher. This is broken: when the applet does get launched at all, the applet process doesn't actually get terminated when the applet gets closed.
|
||||
* @param appID ID of the applet to launch.
|
||||
* @param inhandle Handle to pass to the applet.
|
||||
* @param parambuf Buffer containing applet parameters.
|
||||
* @param parambufsize Size of parambuf.
|
||||
*/
|
||||
Result APT_LaunchLibraryApplet(NS_APPID appID, Handle inhandle, u32 *parambuf, u32 parambufsize);
|
||||
Result APT_StartLibraryApplet(NS_APPID appID, const void* param, size_t paramSize, Handle handle);
|
||||
|
||||
/**
|
||||
* @brief Prepares to start a system applet.
|
||||
* @param appID ID of the applet to start.
|
||||
* @param appID AppID of the applet to start.
|
||||
*/
|
||||
Result APT_PrepareToStartSystemApplet(NS_APPID appID);
|
||||
|
||||
/**
|
||||
* @brief Starts a system applet.
|
||||
* @param appID ID of the applet to launch.
|
||||
* @param bufSize Size of the parameter buffer.
|
||||
* @param applHandle Handle to pass to the applet.
|
||||
* @param buf Buffer containing applet parameters.
|
||||
* @param appID AppID of the applet to launch.
|
||||
* @param param Buffer containing applet parameters.
|
||||
* @param paramSize Size of the parameter buffer.
|
||||
* @param handle Handle to pass to the applet.
|
||||
*/
|
||||
Result APT_StartSystemApplet(NS_APPID appID, u32 bufSize, Handle applHandle, u8 *buf);
|
||||
Result APT_StartSystemApplet(NS_APPID appID, const void* param, size_t paramSize, Handle handle);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the shared system font.
|
||||
|
@ -25,12 +25,21 @@ typedef enum {
|
||||
HTTPC_STATUS_DOWNLOAD_READY = 0x7 ///< Download ready.
|
||||
} HTTPC_RequestStatus;
|
||||
|
||||
/// HTTP KeepAlive option.
|
||||
typedef enum {
|
||||
HTTPC_KEEPALIVE_DISABLED = 0x0,
|
||||
HTTPC_KEEPALIVE_ENABLED = 0x1
|
||||
} HTTPC_KeepAlive;
|
||||
|
||||
/// Result code returned when a download is pending.
|
||||
#define HTTPC_RESULTCODE_DOWNLOADPENDING 0xd840a02b
|
||||
|
||||
// Result code returned when asked about a non-existing header
|
||||
// Result code returned when asked about a non-existing header.
|
||||
#define HTTPC_RESULTCODE_NOTFOUND 0xd840a028
|
||||
|
||||
// Result code returned when any timeout function times out.
|
||||
#define HTTPC_RESULTCODE_TIMEDOUT 0xd820a069
|
||||
|
||||
/// Initializes HTTPC. For HTTP GET the sharedmem_size can be zero. The sharedmem contains data which will be later uploaded for HTTP POST. sharedmem_size should be aligned to 0x1000-bytes.
|
||||
Result httpcInit(u32 sharedmem_size);
|
||||
|
||||
@ -43,7 +52,7 @@ void httpcExit(void);
|
||||
* @param url URL to connect to.
|
||||
* @param use_defaultproxy Whether the default proxy should be used (0 for default)
|
||||
*/
|
||||
Result httpcOpenContext(httpcContext *context, HTTPC_RequestMethod method, char* url, u32 use_defaultproxy);
|
||||
Result httpcOpenContext(httpcContext *context, HTTPC_RequestMethod method, const char* url, u32 use_defaultproxy);
|
||||
|
||||
/**
|
||||
* @brief Closes a HTTP context.
|
||||
@ -51,13 +60,19 @@ Result httpcOpenContext(httpcContext *context, HTTPC_RequestMethod method, char*
|
||||
*/
|
||||
Result httpcCloseContext(httpcContext *context);
|
||||
|
||||
/**
|
||||
* @brief Cancels a HTTP connection.
|
||||
* @param context Context to close.
|
||||
*/
|
||||
Result httpcCancelConnection(httpcContext *context);
|
||||
|
||||
/**
|
||||
* @brief Adds a request header field to a HTTP context.
|
||||
* @param context Context to use.
|
||||
* @param name Name of the field.
|
||||
* @param value Value of the field.
|
||||
*/
|
||||
Result httpcAddRequestHeaderField(httpcContext *context, char* name, char* value);
|
||||
Result httpcAddRequestHeaderField(httpcContext *context, const char* name, const char* value);
|
||||
|
||||
/**
|
||||
* @brief Adds a POST form field to a HTTP context.
|
||||
@ -65,7 +80,7 @@ Result httpcAddRequestHeaderField(httpcContext *context, char* name, char* value
|
||||
* @param name Name of the field.
|
||||
* @param value Value of the field.
|
||||
*/
|
||||
Result httpcAddPostDataAscii(httpcContext *context, char* name, char* value);
|
||||
Result httpcAddPostDataAscii(httpcContext *context, const char* name, const char* value);
|
||||
|
||||
/**
|
||||
* @brief Adds a POST body to a HTTP context.
|
||||
@ -73,7 +88,7 @@ Result httpcAddPostDataAscii(httpcContext *context, char* name, char* value);
|
||||
* @param data The data to be passed as raw into the body of the post request.
|
||||
* @param len Length of data passed by data param.
|
||||
*/
|
||||
Result httpcAddPostDataRaw(httpcContext *context, u32* data, u32 len);
|
||||
Result httpcAddPostDataRaw(httpcContext *context, const u32* data, u32 len);
|
||||
|
||||
/**
|
||||
* @brief Begins a HTTP request.
|
||||
@ -89,6 +104,15 @@ Result httpcBeginRequest(httpcContext *context);
|
||||
*/
|
||||
Result httpcReceiveData(httpcContext *context, u8* buffer, u32 size);
|
||||
|
||||
/**
|
||||
* @brief Receives data from a HTTP context with a timeout value.
|
||||
* @param context Context to use.
|
||||
* @param buffer Buffer to receive data to.
|
||||
* @param size Size of the buffer.
|
||||
* @param timeout Maximum time in nanoseconds to wait for a reply.
|
||||
*/
|
||||
Result httpcReceiveDataTimeout(httpcContext *context, u8* buffer, u32 size, u64 timeout);
|
||||
|
||||
/**
|
||||
* @brief Gets the request state of a HTTP context.
|
||||
* @param context Context to use.
|
||||
@ -108,9 +132,16 @@ Result httpcGetDownloadSizeState(httpcContext *context, u32* downloadedsize, u32
|
||||
* @brief Gets the response code of the HTTP context.
|
||||
* @param context Context to get the response code of.
|
||||
* @param out Pointer to write the response code to.
|
||||
* @param delay Delay to wait for the status code. Not used yet.
|
||||
*/
|
||||
Result httpcGetResponseStatusCode(httpcContext *context, u32* out, u64 delay);
|
||||
Result httpcGetResponseStatusCode(httpcContext *context, u32* out);
|
||||
|
||||
/**
|
||||
* @brief Gets the response code of the HTTP context with a timeout value.
|
||||
* @param context Context to get the response code of.
|
||||
* @param out Pointer to write the response code to.
|
||||
* @param timeout Maximum time in nanoseconds to wait for a reply.
|
||||
*/
|
||||
Result httpcGetResponseStatusCodeTimeout(httpcContext *context, u32* out, u64 timeout);
|
||||
|
||||
/**
|
||||
* @brief Gets a response header field from a HTTP context.
|
||||
@ -119,7 +150,7 @@ Result httpcGetResponseStatusCode(httpcContext *context, u32* out, u64 delay);
|
||||
* @param value Pointer to output the value of the field to.
|
||||
* @param valuebuf_maxsize Maximum size of the value buffer.
|
||||
*/
|
||||
Result httpcGetResponseHeader(httpcContext *context, char* name, char* value, u32 valuebuf_maxsize);
|
||||
Result httpcGetResponseHeader(httpcContext *context, const char* name, char* value, u32 valuebuf_maxsize);
|
||||
|
||||
/**
|
||||
* @brief Adds a trusted RootCA cert to a HTTP context.
|
||||
@ -127,7 +158,7 @@ Result httpcGetResponseHeader(httpcContext *context, char* name, char* value, u3
|
||||
* @param cert Pointer to DER cert.
|
||||
* @param certsize Size of the DER cert.
|
||||
*/
|
||||
Result httpcAddTrustedRootCA(httpcContext *context, u8 *cert, u32 certsize);
|
||||
Result httpcAddTrustedRootCA(httpcContext *context, const u8 *cert, u32 certsize);
|
||||
|
||||
/**
|
||||
* @brief Adds a default RootCA cert to a HTTP context.
|
||||
@ -151,7 +182,7 @@ Result httpcSelectRootCertChain(httpcContext *context, u32 RootCertChain_context
|
||||
* @param privk Pointer to the DER private key.
|
||||
* @param privk_size Size of the privk.
|
||||
*/
|
||||
Result httpcSetClientCert(httpcContext *context, u8 *cert, u32 certsize, u8 *privk, u32 privk_size);
|
||||
Result httpcSetClientCert(httpcContext *context, const u8 *cert, u32 certsize, const u8 *privk, u32 privk_size);
|
||||
|
||||
/**
|
||||
* @brief Sets the default clientcert for a HTTP context.
|
||||
@ -202,7 +233,7 @@ Result httpcDestroyRootCertChain(u32 RootCertChain_contexthandle);
|
||||
* @param certsize Size of the DER cert.
|
||||
* @param cert_contexthandle Optional output ptr for the cert contexthandle(this can be NULL).
|
||||
*/
|
||||
Result httpcRootCertChainAddCert(u32 RootCertChain_contexthandle, u8 *cert, u32 certsize, u32 *cert_contexthandle);
|
||||
Result httpcRootCertChainAddCert(u32 RootCertChain_contexthandle, const u8 *cert, u32 certsize, u32 *cert_contexthandle);
|
||||
|
||||
/**
|
||||
* @brief Adds a default RootCA cert to a RootCertChain.
|
||||
@ -227,7 +258,7 @@ Result httpcRootCertChainRemoveCert(u32 RootCertChain_contexthandle, u32 cert_co
|
||||
* @param privk_size Size of the privk.
|
||||
* @param ClientCert_contexthandle Output ClientCert context handle.
|
||||
*/
|
||||
Result httpcOpenClientCertContext(u8 *cert, u32 certsize, u8 *privk, u32 privk_size, u32 *ClientCert_contexthandle);
|
||||
Result httpcOpenClientCertContext(const u8 *cert, u32 certsize, const u8 *privk, u32 privk_size, u32 *ClientCert_contexthandle);
|
||||
|
||||
/**
|
||||
* @brief Opens a ClientCert-context with a default clientclient. Up to 2 ClientCert-contexts can be open under this user-process.
|
||||
@ -252,3 +283,10 @@ Result httpcCloseClientCertContext(u32 ClientCert_contexthandle);
|
||||
*/
|
||||
Result httpcDownloadData(httpcContext *context, u8* buffer, u32 size, u32 *downloadedsize);
|
||||
|
||||
/**
|
||||
* @brief Sets Keep-Alive for the context.
|
||||
* @param context Context to set the KeepAlive flag on.
|
||||
* @param option HTTPC_KeepAlive option.
|
||||
*/
|
||||
Result httpcSetKeepAlive(httpcContext *context, HTTPC_KeepAlive option);
|
||||
|
||||
|
@ -74,3 +74,10 @@ Result PS_GetLocalFriendCodeSeed(u64* seed);
|
||||
* @param device_id Pointer to write the device ID to.
|
||||
*/
|
||||
Result PS_GetDeviceId(u32* device_id);
|
||||
|
||||
/**
|
||||
* @brief Generates cryptographically secure random bytes.
|
||||
* @param out Pointer to the buffer to write the bytes to.
|
||||
* @param len Number of bytes to write.
|
||||
*/
|
||||
Result PS_GenerateRandomBytes(void* out, size_t len);
|
||||
|
79
libctru/include/3ds/services/pxidev.h
Normal file
79
libctru/include/3ds/services/pxidev.h
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @file pxidev.h
|
||||
* @brief Gamecard PXI service.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <3ds/services/fs.h>
|
||||
|
||||
/// Card SPI wait operation type.
|
||||
typedef enum {
|
||||
WAIT_NONE = 0, ///< Do not wait.
|
||||
WAIT_SLEEP = 1, ///< Sleep for the specified number of nanoseconds.
|
||||
WAIT_IREQ_RETURN = 2, ///< Wait for IREQ, return if timeout.
|
||||
WAIT_IREQ_CONTINUE = 3 ///< Wait for IREQ, continue if timeout.
|
||||
} PXIDEV_WaitType;
|
||||
|
||||
/// Card SPI register deassertion type.
|
||||
typedef enum {
|
||||
DEASSERT_NONE = 0, ///< Do not deassert.
|
||||
DEASSERT_BEFORE_WAIT = 1, ///< Deassert before waiting.
|
||||
DEASSERT_AFTER_WAIT = 2 ///< Deassert after waiting.
|
||||
} PXIDEV_DeassertType;
|
||||
|
||||
/// Card SPI transfer buffer.
|
||||
typedef struct {
|
||||
void* ptr; ///< Data pointer.
|
||||
u32 size; ///< Data size.
|
||||
u8 transferOption; ///< Transfer options. See @ref pxiDevMakeTransferOption
|
||||
u64 waitOperation; ///< Wait operation. See @ref pxiDevMakeWaitOperation
|
||||
} PXIDEV_SPIBuffer;
|
||||
|
||||
/// Initializes pxi:dev.
|
||||
Result pxiDevInit(void);
|
||||
|
||||
/// Shuts down pxi:dev.
|
||||
void pxiDevExit(void);
|
||||
|
||||
/**
|
||||
* @brief Creates a packed card SPI transfer option value.
|
||||
* @param baudRate Baud rate to use when transferring.
|
||||
* @param busMode Bus mode to use when transferring.
|
||||
* @return A packed card SPI transfer option value.
|
||||
*/
|
||||
static inline u8 pxiDevMakeTransferOption(FS_CardSpiBaudRate baudRate, FS_CardSpiBusMode busMode)
|
||||
{
|
||||
return (baudRate & 0x3F) | ((busMode & 0x3) << 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a packed card SPI wait operation value.
|
||||
* @param waitType Type of wait to perform.
|
||||
* @param deassertType Type of register deassertion to perform.
|
||||
* @param timeout Timeout, in nanoseconds, to wait, if applicable.
|
||||
* @return A packed card SPI wait operation value.
|
||||
*/
|
||||
static inline u64 pxiDevMakeWaitOperation(PXIDEV_WaitType waitType, PXIDEV_DeassertType deassertType, u64 timeout)
|
||||
{
|
||||
return (waitType & 0xF) | ((deassertType & 0xF) << 4) | ((timeout & 0xFFFFFFFFFFFFFF) << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs multiple card SPI writes and reads.
|
||||
* @param header Header to lead the transfers with. Must be, at most, 8 bytes in size.
|
||||
* @param writeBuffer1 Buffer to make first transfer from.
|
||||
* @param readBuffer1 Buffer to receive first response to.
|
||||
* @param writeBuffer2 Buffer to make second transfer from.
|
||||
* @param readBuffer2 Buffer to receive second response to.
|
||||
* @param footer Footer to follow the transfers with. Must be, at most, 8 bytes in size. Wait operation is unused.
|
||||
*/
|
||||
Result PXIDEV_SPIMultiWriteRead(PXIDEV_SPIBuffer* header, PXIDEV_SPIBuffer* writeBuffer1, PXIDEV_SPIBuffer* readBuffer1, PXIDEV_SPIBuffer* writeBuffer2, PXIDEV_SPIBuffer* readBuffer2, PXIDEV_SPIBuffer* footer);
|
||||
|
||||
/**
|
||||
* @brief Performs a single card SPI write and read.
|
||||
* @param bytesRead Pointer to output the number of bytes received to.
|
||||
* @param initialWaitOperation Wait operation to perform before transferring data.
|
||||
* @param writeBuffer Buffer to transfer data from.
|
||||
* @param readBuffer Buffer to receive data to.
|
||||
*/
|
||||
Result PXIDEV_SPIWriteRead(u32* bytesRead, u64 initialWaitOperation, PXIDEV_SPIBuffer* writeBuffer, PXIDEV_SPIBuffer* readBuffer);
|
@ -14,16 +14,17 @@
|
||||
/// Options to be used with @ref SOCU_GetNetworkOpt
|
||||
typedef enum
|
||||
{
|
||||
NETOPT_MAC_ADDRESS = 0x1004, ///< The mac address of the interface (u32 mac[6])
|
||||
NETOPT_ARP_TABLE = 0x3002, ///< The ARP table @see SOCU_ARPTableEntry
|
||||
NETOPT_IP_INFO = 0x4003, ///< The cureent IP setup @see SOCU_IPInfo
|
||||
NETOPT_IP_MTU = 0x4004, ///< The value of the IP MTU (u32)
|
||||
NETOPT_ROUTING_TABLE = 0x4006, ///< The routing table @see SOCU_RoutingTableEntry
|
||||
NETOPT_UDP_NUMBER = 0x8002, ///< The number of sockets in the UDP table (u32)
|
||||
NETOPT_UDP_TABLE = 0x8003, ///< The table of opened UDP sockets @see SOCU_UDPTableEntry
|
||||
NETOPT_TCP_NUMBER = 0x9002, ///< The number of sockets in the TCP table (u32)
|
||||
NETOPT_TCP_TABLE = 0x9003, ///< The table of opened TCP sockets @see SOCU_TCPTableEntry
|
||||
NETOPT_DNS_TABLE = 0xB003, ///< The table of the DNS servers @see SOCU_DNSTableEntry -- Returns a buffer of size 336 but only 2 entries are set ?
|
||||
NETOPT_MAC_ADDRESS = 0x1004, ///< The mac address of the interface (u32 mac[6])
|
||||
NETOPT_ARP_TABLE = 0x3002, ///< The ARP table @see SOCU_ARPTableEntry
|
||||
NETOPT_IP_INFO = 0x4003, ///< The cureent IP setup @see SOCU_IPInfo
|
||||
NETOPT_IP_MTU = 0x4004, ///< The value of the IP MTU (u32)
|
||||
NETOPT_ROUTING_TABLE = 0x4006, ///< The routing table @see SOCU_RoutingTableEntry
|
||||
NETOPT_UDP_NUMBER = 0x8002, ///< The number of sockets in the UDP table (u32)
|
||||
NETOPT_UDP_TABLE = 0x8003, ///< The table of opened UDP sockets @see SOCU_UDPTableEntry
|
||||
NETOPT_TCP_NUMBER = 0x9002, ///< The number of sockets in the TCP table (u32)
|
||||
NETOPT_TCP_TABLE = 0x9003, ///< The table of opened TCP sockets @see SOCU_TCPTableEntry
|
||||
NETOPT_DNS_TABLE = 0xB003, ///< The table of the DNS servers @see SOCU_DNSTableEntry -- Returns a buffer of size 336 but only 2 entries are set ?
|
||||
NETOPT_DHCP_LEASE_TIME = 0xC001, ///< The DHCP lease time remaining, in seconds
|
||||
} NetworkOpt;
|
||||
|
||||
/// One entry of the ARP table retrieved by using @ref SOCU_GetNetworkOpt and @ref NETOPT_ARP_TABLE
|
||||
|
@ -60,7 +60,7 @@ Result sslcDestroyRootCertChain(u32 RootCertChain_contexthandle);
|
||||
* @param cert Pointer to the DER cert.
|
||||
* @param certsize Size of the DER cert.
|
||||
*/
|
||||
Result sslcAddTrustedRootCA(u32 RootCertChain_contexthandle, u8 *cert, u32 certsize, u32 *cert_contexthandle);
|
||||
Result sslcAddTrustedRootCA(u32 RootCertChain_contexthandle, const u8 *cert, u32 certsize, u32 *cert_contexthandle);
|
||||
|
||||
/**
|
||||
* @brief Adds a default RootCA cert to a RootCertChain.
|
||||
@ -95,7 +95,7 @@ Result sslcDestroy8CertChain(u32 CertChain_contexthandle);
|
||||
* @param cert Pointer to the cert.
|
||||
* @param certsize Size of the cert.
|
||||
*/
|
||||
Result sslc8CertChainAddCert(u32 CertChain_contexthandle, u8 *cert, u32 certsize, u32 *cert_contexthandle);
|
||||
Result sslc8CertChainAddCert(u32 CertChain_contexthandle, const u8 *cert, u32 certsize, u32 *cert_contexthandle);
|
||||
|
||||
/**
|
||||
* @brief Adds a default cert to a CertChain from sslcCreate8CertChain(). Not actually usable since no certIDs are implemented in SSL-module for this.
|
||||
@ -120,7 +120,7 @@ Result sslc8CertChainRemoveCert(u32 CertChain_contexthandle, u32 cert_contexthan
|
||||
* @param keysize Size of the DER key.
|
||||
* @param ClientCert_contexthandle Output contexthandle.
|
||||
*/
|
||||
Result sslcOpenClientCertContext(u8 *cert, u32 certsize, u8 *key, u32 keysize, u32 *ClientCert_contexthandle);
|
||||
Result sslcOpenClientCertContext(const u8 *cert, u32 certsize, const u8 *key, u32 keysize, u32 *ClientCert_contexthandle);
|
||||
|
||||
/**
|
||||
* @brief Opens a ClientCert-context with a default certID.
|
||||
@ -154,7 +154,7 @@ Result sslcGenerateRandomData(u8 *buf, u32 size);
|
||||
* @param input_opt Input sslc options bitmask.
|
||||
* @param hostname Server hostname.
|
||||
*/
|
||||
Result sslcCreateContext(sslcContext *context, int sockfd, u32 input_opt, char *hostname);
|
||||
Result sslcCreateContext(sslcContext *context, int sockfd, u32 input_opt, const char *hostname);
|
||||
|
||||
/*
|
||||
* @brief Destroys a sslc context. The associated sockfd must be closed manually.
|
||||
@ -187,7 +187,7 @@ Result sslcRead(sslcContext *context, void *buf, size_t len, bool peek);
|
||||
* @param len Size to send.
|
||||
* @return When this isn't an error-code, this is the total transferred data size.
|
||||
*/
|
||||
Result sslcWrite(sslcContext *context, void *buf, size_t len);
|
||||
Result sslcWrite(sslcContext *context, const void *buf, size_t len);
|
||||
|
||||
/*
|
||||
* @brief Set the RootCertChain for the specified sslc context.
|
||||
@ -247,5 +247,5 @@ Result sslcContextInitSharedmem(sslcContext *context, u8 *buf, u32 size);
|
||||
* @param buf Input cert.
|
||||
* @param size Cert size.
|
||||
*/
|
||||
Result sslcAddCert(sslcContext *context, u8 *buf, u32 size);
|
||||
Result sslcAddCert(sslcContext *context, const u8 *buf, u32 size);
|
||||
|
||||
|
@ -90,6 +90,13 @@ typedef enum {
|
||||
///@name Multithreading
|
||||
///@{
|
||||
|
||||
/// Reset types (for use with events and timers)
|
||||
typedef enum {
|
||||
RESET_ONESHOT = 0, ///< When the primitive is signaled, it will wake up exactly one thread and will clear itself automatically.
|
||||
RESET_STICKY = 1, ///< When the primitive is signaled, it will wake up all threads and it won't clear itself automatically.
|
||||
RESET_PULSE = 2, ///< Only meaningful for timers: same as ONESHOT but it will periodically signal the timer instead of just once.
|
||||
} ResetType;
|
||||
|
||||
/// Types of thread info.
|
||||
typedef enum {
|
||||
THREADINFO_TYPE_UNKNOWN ///< Unknown.
|
||||
@ -741,9 +748,9 @@ Result svcReleaseSemaphore(s32* count, Handle semaphore, s32 release_count);
|
||||
/**
|
||||
* @brief Creates an event handle.
|
||||
* @param[out] event Pointer to output the created event handle to.
|
||||
* @param reset_type Type of reset the event uses.
|
||||
* @param reset_type Type of reset the event uses (RESET_ONESHOT/RESET_STICKY).
|
||||
*/
|
||||
Result svcCreateEvent(Handle* event, u8 reset_type);
|
||||
Result svcCreateEvent(Handle* event, ResetType reset_type);
|
||||
|
||||
/**
|
||||
* @brief Signals an event.
|
||||
@ -821,6 +828,22 @@ Result svcAcceptSession(Handle* session, Handle port);
|
||||
* @param replyTarget Handle of the session to reply to.
|
||||
*/
|
||||
Result svcReplyAndReceive(s32* index, Handle* handles, s32 handleCount, Handle replyTarget);
|
||||
|
||||
/**
|
||||
* @brief Binds an event handle to an ARM11 interrupt.
|
||||
* @param interruptId Interrupt identfier (see https://www.3dbrew.org/wiki/ARM11_Interrupts).
|
||||
* @param event Event handle to bind to the given interrupt.
|
||||
* @param priority Priority of the interrupt for the current process.
|
||||
* @param isManualClear Indicates whether the interrupt has to be manually cleared or not.
|
||||
*/
|
||||
Result svcBindInterrupt(u32 interruptId, Handle event, s32 priority, bool isManualClear);
|
||||
|
||||
/**
|
||||
* @brief Unbinds an event handle from an ARM11 interrupt.
|
||||
* @param interruptId Interrupt identfier, see (see https://www.3dbrew.org/wiki/ARM11_Interrupts).
|
||||
* @param event Event handle to unbind from the given interrupt.
|
||||
*/
|
||||
Result svcUnbindInterrupt(u32 interruptId, Handle event);
|
||||
///@}
|
||||
|
||||
///@name Time
|
||||
@ -830,7 +853,7 @@ Result svcReplyAndReceive(s32* index, Handle* handles, s32 handleCount, Handle r
|
||||
* @param[out] timer Pointer to output the handle of the created timer to.
|
||||
* @param reset_type Type of reset to perform on the timer.
|
||||
*/
|
||||
Result svcCreateTimer(Handle* timer, u8 reset_type);
|
||||
Result svcCreateTimer(Handle* timer, ResetType reset_type);
|
||||
|
||||
/**
|
||||
* @brief Sets a timer.
|
||||
|
@ -11,6 +11,13 @@ typedef _LOCK_T LightLock;
|
||||
/// A recursive lock.
|
||||
typedef _LOCK_RECURSIVE_T RecursiveLock;
|
||||
|
||||
/// A light event.
|
||||
typedef struct
|
||||
{
|
||||
s32 state; ///< State of the event: -2=cleared sticky, -1=cleared oneshot, 0=signaled oneshot, 1=signaled sticky
|
||||
LightLock lock; ///< Lock used for sticky timer operation
|
||||
} LightEvent;
|
||||
|
||||
/// Performs a Data Synchronization Barrier operation.
|
||||
static inline void __dsb(void)
|
||||
{
|
||||
@ -114,3 +121,41 @@ int RecursiveLock_TryLock(RecursiveLock* lock);
|
||||
* @param lock Pointer to the lock.
|
||||
*/
|
||||
void RecursiveLock_Unlock(RecursiveLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Initializes a light event.
|
||||
* @param event Pointer to the event.
|
||||
* @param reset_type Type of reset the event uses (RESET_ONESHOT/RESET_STICKY).
|
||||
*/
|
||||
void LightEvent_Init(LightEvent* event, ResetType reset_type);
|
||||
|
||||
/**
|
||||
* @brief Clears a light event.
|
||||
* @param event Pointer to the event.
|
||||
*/
|
||||
void LightEvent_Clear(LightEvent* event);
|
||||
|
||||
/**
|
||||
* @brief Wakes up threads waiting on a sticky light event without signaling it. If the event had been signaled before, it is cleared instead.
|
||||
* @param event Pointer to the event.
|
||||
*/
|
||||
void LightEvent_Pulse(LightEvent* event);
|
||||
|
||||
/**
|
||||
* @brief Signals a light event, waking up threads waiting on it.
|
||||
* @param event Pointer to the event.
|
||||
*/
|
||||
void LightEvent_Signal(LightEvent* event);
|
||||
|
||||
/**
|
||||
* @brief Attempts to wait on a light event.
|
||||
* @param event Pointer to the event.
|
||||
* @return Non-zero if the event was signaled, zero otherwise.
|
||||
*/
|
||||
int LightEvent_TryWait(LightEvent* event);
|
||||
|
||||
/**
|
||||
* @brief Waits on a light event.
|
||||
* @param event Pointer to the event.
|
||||
*/
|
||||
void LightEvent_Wait(LightEvent* event);
|
||||
|
276
libctru/source/applets/swkbd.c
Normal file
276
libctru/source/applets/swkbd.c
Normal file
@ -0,0 +1,276 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/synchronization.h>
|
||||
#include <3ds/services/apt.h>
|
||||
#include <3ds/applets/swkbd.h>
|
||||
#include <3ds/ipc.h>
|
||||
#include <3ds/env.h>
|
||||
#include <3ds/util/utf.h>
|
||||
|
||||
static char* swkbdSharedMem;
|
||||
static Handle swkbdSharedMemHandle;
|
||||
|
||||
void swkbdInit(SwkbdState* swkbd, SwkbdType type, int numButtons, int maxTextLength)
|
||||
{
|
||||
memset(swkbd, 0, sizeof(*swkbd));
|
||||
swkbd->type = type;
|
||||
swkbd->num_buttons_m1 = numButtons-1;
|
||||
swkbd->max_text_len = maxTextLength > 0 ? maxTextLength : 0xFDE8;
|
||||
swkbd->button_submits_text[SWKBD_BUTTON_CONFIRM] = true;
|
||||
swkbd->initial_text_offset = -1;
|
||||
swkbd->dict_offset = -1;
|
||||
swkbd->initial_status_offset = -1;
|
||||
swkbd->initial_learning_offset = -1;
|
||||
swkbd->version = 5;
|
||||
swkbd->result = SWKBD_NONE;
|
||||
swkbd->status_offset = -1;
|
||||
swkbd->learning_offset = -1;
|
||||
swkbd->text_offset = -1;
|
||||
}
|
||||
|
||||
static void swkbdConvertToUTF8(char* out, const u16* in, int max)
|
||||
{
|
||||
if (!in || !*in)
|
||||
{
|
||||
out[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t units = utf16_to_utf8((uint8_t*)out, in, max);
|
||||
if (units < 0)
|
||||
{
|
||||
out[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
out[units] = 0;
|
||||
}
|
||||
|
||||
static void swkbdConvertToUTF16(u16* out, const char* in, int max)
|
||||
{
|
||||
if (!in || !*in)
|
||||
{
|
||||
out[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t units = utf8_to_utf16(out, (const uint8_t*)in, max);
|
||||
if (units < 0)
|
||||
{
|
||||
out[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
out[units] = 0;
|
||||
}
|
||||
|
||||
static const u16 swkbdFeatures[] =
|
||||
{
|
||||
offsetof(SwkbdState, is_parental_screen),
|
||||
offsetof(SwkbdState, darken_top_screen),
|
||||
offsetof(SwkbdState, predictive_input),
|
||||
offsetof(SwkbdState, multiline),
|
||||
offsetof(SwkbdState, fixed_width),
|
||||
offsetof(SwkbdState, allow_home),
|
||||
offsetof(SwkbdState, allow_reset),
|
||||
offsetof(SwkbdState, allow_power),
|
||||
offsetof(SwkbdState, unknown),
|
||||
offsetof(SwkbdState, default_qwerty),
|
||||
};
|
||||
|
||||
void swkbdSetFeatures(SwkbdState* swkbd, u32 features)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (sizeof(swkbdFeatures)/sizeof(u16)); i ++)
|
||||
*((u8*)swkbd + swkbdFeatures[i]) = (features & BIT(i)) ? 1 : 0;
|
||||
}
|
||||
|
||||
void swkbdSetHintText(SwkbdState* swkbd, const char* text)
|
||||
{
|
||||
swkbdConvertToUTF16(swkbd->hint_text, text, SWKBD_MAX_HINT_TEXT_LEN);
|
||||
}
|
||||
|
||||
void swkbdSetButton(SwkbdState* swkbd, SwkbdButton button, const char* text, bool submit)
|
||||
{
|
||||
swkbdConvertToUTF16(swkbd->button_text[button], text, SWKBD_MAX_BUTTON_TEXT_LEN);
|
||||
swkbd->button_submits_text[button] = submit;
|
||||
}
|
||||
|
||||
void swkbdSetInitialText(SwkbdState* swkbd, const char* text)
|
||||
{
|
||||
swkbd->extra.initial_text = text;
|
||||
}
|
||||
|
||||
void swkbdSetDictWord(SwkbdDictWord* word, const char* reading, const char* text)
|
||||
{
|
||||
swkbdConvertToUTF16(word->reading, reading, SWKBD_MAX_WORD_LEN);
|
||||
swkbdConvertToUTF16(word->word, text, SWKBD_MAX_WORD_LEN);
|
||||
word->language = 0;
|
||||
word->all_languages = true;
|
||||
}
|
||||
|
||||
void swkbdSetDictionary(SwkbdState* swkbd, const SwkbdDictWord* dict, int wordCount)
|
||||
{
|
||||
swkbd->dict_word_count = dict ? wordCount : 0;
|
||||
swkbd->extra.dict = dict;
|
||||
}
|
||||
|
||||
void swkbdSetStatusData(SwkbdState* swkbd, SwkbdStatusData* data, bool in, bool out)
|
||||
{
|
||||
swkbd->extra.status_data = data;
|
||||
swkbd->initial_status_offset = (data&&in) ? 0 : -1;
|
||||
if (data&&out) swkbd->save_state_flags |= BIT(0);
|
||||
else swkbd->save_state_flags &= ~BIT(0);
|
||||
}
|
||||
|
||||
void swkbdSetLearningData(SwkbdState* swkbd, SwkbdLearningData* data, bool in, bool out)
|
||||
{
|
||||
swkbd->extra.learning_data = data;
|
||||
swkbd->initial_learning_offset = (data&&in) ? 0 : -1;
|
||||
if (data&&out) swkbd->save_state_flags |= BIT(1);
|
||||
else swkbd->save_state_flags &= ~BIT(1);
|
||||
}
|
||||
|
||||
void swkbdSetFilterCallback(SwkbdState* swkbd, SwkbdCallbackFn callback, void* user)
|
||||
{
|
||||
swkbd->extra.callback = callback;
|
||||
swkbd->extra.callback_user = callback ? user : NULL;
|
||||
}
|
||||
|
||||
static void swkbdMessageCallback(void* user, NS_APPID sender, void* msg, size_t msgsize)
|
||||
{
|
||||
SwkbdExtra* extra = (SwkbdExtra*)user;
|
||||
SwkbdState* swkbd = (SwkbdState*)msg;
|
||||
|
||||
if (sender != APPID_SOFTWARE_KEYBOARD || msgsize != sizeof(SwkbdState))
|
||||
return;
|
||||
|
||||
u16* text16 = (u16*)(swkbdSharedMem + swkbd->text_offset);
|
||||
ssize_t units = utf16_to_utf8(NULL, text16, 0);
|
||||
if (units < 0) svcBreak(USERBREAK_PANIC); // Shouldn't happen.
|
||||
char* text8 = (char*)malloc(units+1);
|
||||
if (!text8) svcBreak(USERBREAK_PANIC); // Shouldn't happen.
|
||||
swkbdConvertToUTF8(text8, text16, units);
|
||||
|
||||
const char* retmsg = NULL;
|
||||
swkbd->callback_result = extra->callback(extra->callback_user, &retmsg, text8, units);
|
||||
if (swkbd->callback_result > SWKBD_CALLBACK_OK)
|
||||
swkbdConvertToUTF16(swkbd->callback_msg, retmsg, SWKBD_MAX_CALLBACK_MSG_LEN);
|
||||
else
|
||||
swkbd->callback_msg[0] = 0;
|
||||
|
||||
free(text8);
|
||||
APT_SendParameter(envGetAptAppId(), sender, APTCMD_MESSAGE, swkbd, sizeof(*swkbd), 0);
|
||||
}
|
||||
|
||||
SwkbdButton swkbdInputText(SwkbdState* swkbd, char* buf, size_t bufsize)
|
||||
{
|
||||
SwkbdExtra extra = swkbd->extra; // Struct copy
|
||||
|
||||
// Calculate sharedmem size
|
||||
size_t sharedMemSize = 0;
|
||||
sharedMemSize += (sizeof(u16)*(swkbd->max_text_len+1) + 3) &~ 3;
|
||||
size_t dictOff = sharedMemSize;
|
||||
sharedMemSize += (sizeof(SwkbdDictWord)*swkbd->dict_word_count + 3) &~ 3;
|
||||
size_t statusOff = sharedMemSize;
|
||||
sharedMemSize += swkbd->initial_status_offset >= 0 ? sizeof(SwkbdStatusData) : 0;
|
||||
size_t learningOff = sharedMemSize;
|
||||
sharedMemSize += swkbd->initial_learning_offset >= 0 ? sizeof(SwkbdLearningData) : 0;
|
||||
if (swkbd->save_state_flags & BIT(0))
|
||||
{
|
||||
swkbd->status_offset = sharedMemSize;
|
||||
sharedMemSize += sizeof(SwkbdStatusData);
|
||||
}
|
||||
if (swkbd->save_state_flags & BIT(1))
|
||||
{
|
||||
swkbd->learning_offset = sharedMemSize;
|
||||
sharedMemSize += sizeof(SwkbdLearningData);
|
||||
}
|
||||
sharedMemSize = (sharedMemSize + 0xFFF) &~ 0xFFF;
|
||||
swkbd->shared_memory_size = sharedMemSize;
|
||||
|
||||
// Allocate sharedmem
|
||||
swkbdSharedMem = (char*)memalign(0x1000, sharedMemSize);
|
||||
if (!swkbdSharedMem)
|
||||
{
|
||||
swkbd->result = SWKBD_OUTOFMEM;
|
||||
return SWKBD_BUTTON_NONE;
|
||||
}
|
||||
|
||||
// Create sharedmem block
|
||||
Result res = svcCreateMemoryBlock(&swkbdSharedMemHandle, (u32)swkbdSharedMem, sharedMemSize, MEMPERM_READ|MEMPERM_WRITE, MEMPERM_READ|MEMPERM_WRITE);
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
free(swkbdSharedMem);
|
||||
swkbd->result = SWKBD_OUTOFMEM;
|
||||
return SWKBD_BUTTON_NONE;
|
||||
}
|
||||
|
||||
// Copy stuff to shared mem
|
||||
if (extra.initial_text)
|
||||
{
|
||||
swkbd->initial_text_offset = 0;
|
||||
swkbdConvertToUTF16((u16*)swkbdSharedMem, extra.initial_text, swkbd->max_text_len);
|
||||
}
|
||||
if (extra.dict)
|
||||
{
|
||||
swkbd->dict_offset = dictOff;
|
||||
memcpy(swkbdSharedMem+dictOff, extra.dict, sizeof(SwkbdDictWord)*swkbd->dict_word_count);
|
||||
}
|
||||
if (swkbd->initial_status_offset >= 0)
|
||||
{
|
||||
swkbd->initial_status_offset = statusOff;
|
||||
memcpy(swkbdSharedMem+statusOff, extra.status_data, sizeof(SwkbdStatusData));
|
||||
}
|
||||
if (swkbd->initial_learning_offset >= 0)
|
||||
{
|
||||
swkbd->initial_learning_offset = learningOff;
|
||||
memcpy(swkbdSharedMem+learningOff, extra.learning_data, sizeof(SwkbdLearningData));
|
||||
}
|
||||
|
||||
if (extra.callback) swkbd->filter_flags |= SWKBD_FILTER_CALLBACK;
|
||||
else swkbd->filter_flags &= ~SWKBD_FILTER_CALLBACK;
|
||||
|
||||
// Launch swkbd
|
||||
memset(swkbd->reserved, 0, sizeof(swkbd->reserved));
|
||||
if (extra.callback) aptSetMessageCallback(swkbdMessageCallback, &extra);
|
||||
bool ret = aptLaunchLibraryApplet(APPID_SOFTWARE_KEYBOARD, swkbd, sizeof(*swkbd), swkbdSharedMemHandle);
|
||||
if (extra.callback) aptSetMessageCallback(NULL, NULL);
|
||||
svcCloseHandle(swkbdSharedMemHandle);
|
||||
|
||||
SwkbdButton button = SWKBD_BUTTON_NONE;
|
||||
|
||||
if (ret)
|
||||
{
|
||||
u16* text16 = (u16*)(swkbdSharedMem+swkbd->text_offset);
|
||||
text16[swkbd->text_length] = 0;
|
||||
swkbdConvertToUTF8(buf, text16, bufsize-1);
|
||||
if (swkbd->save_state_flags & BIT(0)) memcpy(extra.status_data, swkbdSharedMem+swkbd->status_offset, sizeof(SwkbdStatusData));
|
||||
if (swkbd->save_state_flags & BIT(1)) memcpy(extra.learning_data, swkbdSharedMem+swkbd->learning_offset, sizeof(SwkbdLearningData));
|
||||
|
||||
switch (swkbd->result)
|
||||
{
|
||||
case SWKBD_D1_CLICK0:
|
||||
case SWKBD_D2_CLICK0:
|
||||
button = SWKBD_BUTTON_LEFT;
|
||||
break;
|
||||
case SWKBD_D2_CLICK1:
|
||||
button = SWKBD_BUTTON_MIDDLE;
|
||||
break;
|
||||
case SWKBD_D0_CLICK:
|
||||
case SWKBD_D1_CLICK1:
|
||||
case SWKBD_D2_CLICK2:
|
||||
button = SWKBD_BUTTON_RIGHT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(swkbdSharedMem);
|
||||
return button;
|
||||
}
|
108
libctru/source/errf.c
Normal file
108
libctru/source/errf.c
Normal file
@ -0,0 +1,108 @@
|
||||
#include <string.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/synchronization.h>
|
||||
#include <3ds/errf.h>
|
||||
#include <3ds/ipc.h>
|
||||
#include <3ds/env.h>
|
||||
#include "internal.h"
|
||||
|
||||
static Handle errfHandle;
|
||||
static int errfRefCount;
|
||||
|
||||
Result errfInit(void)
|
||||
{
|
||||
Result rc = 0;
|
||||
|
||||
if (AtomicPostIncrement(&errfRefCount)) return 0;
|
||||
|
||||
rc = svcConnectToPort(&errfHandle, "err:f");
|
||||
if (R_FAILED(rc)) goto end;
|
||||
|
||||
end:
|
||||
if (R_FAILED(rc)) errfExit();
|
||||
return rc;
|
||||
}
|
||||
|
||||
void errfExit(void)
|
||||
{
|
||||
if (AtomicDecrement(&errfRefCount))
|
||||
return;
|
||||
svcCloseHandle(errfHandle);
|
||||
}
|
||||
|
||||
Handle* errfGetSessionHandle(void)
|
||||
{
|
||||
return &errfHandle;
|
||||
}
|
||||
|
||||
Result ERRF_Throw(const ERRF_FatalErrInfo* error)
|
||||
{
|
||||
uint32_t *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x1,32,0); // 0x10800
|
||||
memcpy(&cmdbuf[1], error, sizeof(ERRF_FatalErrInfo));
|
||||
|
||||
Result ret = 0;
|
||||
if (R_FAILED(ret = svcSendSyncRequest(errfHandle)))
|
||||
return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
static inline void getCommonErrorData(ERRF_FatalErrInfo* error, Result failure)
|
||||
{
|
||||
error->resCode = failure;
|
||||
svcGetProcessId(&error->procId, 0xFFFF8001);
|
||||
}
|
||||
|
||||
Result ERRF_ThrowResult(Result failure)
|
||||
{
|
||||
ERRF_FatalErrInfo error;
|
||||
Result ret;
|
||||
|
||||
if (R_FAILED(ret = errfInit()))
|
||||
return ret;
|
||||
|
||||
memset(&error, 0, sizeof(error));
|
||||
|
||||
error.type = ERRF_ERRTYPE_GENERIC;
|
||||
|
||||
// pcAddr is not used by ErrDisp for ERRF_ERRTYPE_FAILURE
|
||||
error.pcAddr = (u32)__builtin_extract_return_addr(__builtin_return_address(0));
|
||||
getCommonErrorData(&error, failure);
|
||||
|
||||
ret = ERRF_Throw(&error);
|
||||
|
||||
errfExit();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result ERRF_ThrowResultWithMessage(Result failure, const char* message)
|
||||
{
|
||||
ERRF_FatalErrInfo error;
|
||||
Result ret;
|
||||
size_t msglen;
|
||||
|
||||
if (R_FAILED(ret = errfInit()))
|
||||
return ret;
|
||||
|
||||
memset(&error, 0, sizeof(error));
|
||||
|
||||
error.type = ERRF_ERRTYPE_FAILURE;
|
||||
getCommonErrorData(&error, failure);
|
||||
|
||||
if ((msglen = strlen(message)) > sizeof(error.data.failure_mesg) - 1)
|
||||
msglen = sizeof(error.data.failure_mesg) - 1;
|
||||
|
||||
memcpy(error.data.failure_mesg, message, msglen);
|
||||
error.data.failure_mesg[msglen] = '\0';
|
||||
|
||||
ret = ERRF_Throw(&error);
|
||||
|
||||
errfExit();
|
||||
|
||||
return ret;
|
||||
}
|
@ -16,9 +16,7 @@ Result fontEnsureMapped(void)
|
||||
Result res = 0;
|
||||
Handle hSharedFont = 0;
|
||||
|
||||
aptOpenSession();
|
||||
res = APT_GetSharedFont(&hSharedFont, &sharedFontAddr);
|
||||
aptCloseSession();
|
||||
if (R_FAILED(res)) return res;
|
||||
|
||||
// Map the shared font if it's not already mapped.
|
||||
|
@ -56,7 +56,7 @@ void gfxSetDoubleBuffering(gfxScreen_t screen, bool doubleBuffering) {
|
||||
doubleBuf[screen] = doubleBuffering ? 1 : 0; // make sure they're the integer values '1' and '0'
|
||||
}
|
||||
|
||||
static u32 __get_bytes_per_pixel(GSPGPU_FramebufferFormats format) {
|
||||
u32 __get_bytes_per_pixel(GSPGPU_FramebufferFormats format) {
|
||||
switch(format) {
|
||||
case GSP_RGBA8_OES:
|
||||
return 4;
|
||||
@ -129,7 +129,7 @@ void gfxInit(GSPGPU_FramebufferFormats topFormat, GSPGPU_FramebufferFormats bott
|
||||
GSPGPU_AcquireRight(0x0);
|
||||
|
||||
//setup our gsp shared mem section
|
||||
svcCreateEvent(&gspEvent, 0x0);
|
||||
svcCreateEvent(&gspEvent, RESET_ONESHOT);
|
||||
GSPGPU_RegisterInterruptRelayQueue(gspEvent, 0x1, &gspSharedMemHandle, &gfxThreadID);
|
||||
svcMapMemoryBlock(gspSharedMemHandle, (u32)gfxSharedMemory, 0x3, 0x10000000);
|
||||
|
||||
|
@ -1,307 +0,0 @@
|
||||
/*
|
||||
gpu-old.c _ Legacy GPU commands.
|
||||
*/
|
||||
|
||||
#define LIBCTRU_NO_DEPRECATION
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/gpu/gpu.h>
|
||||
#include <3ds/gpu/gpu-old.h>
|
||||
#include <3ds/gpu/gx.h>
|
||||
#include <3ds/gpu/shbin.h>
|
||||
|
||||
|
||||
void GPU_Init(Handle *gsphandle)
|
||||
{
|
||||
gpuCmdBuf=NULL;
|
||||
gpuCmdBufSize=0;
|
||||
gpuCmdBufOffset=0;
|
||||
}
|
||||
|
||||
void GPU_Reset(u32* gxbuf, u32* gpuBuf, u32 gpuBufSize)
|
||||
{
|
||||
GPUCMD_SetBuffer(gpuBuf, gpuBufSize, 0);
|
||||
}
|
||||
|
||||
void GPU_SetFloatUniform(GPU_SHADER_TYPE type, u32 startreg, u32* data, u32 numreg)
|
||||
{
|
||||
if(!data)return;
|
||||
|
||||
int regOffset=(type==GPU_GEOMETRY_SHADER)?(-0x30):(0x0);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_VSH_FLOATUNIFORM_CONFIG+regOffset, 0x80000000|startreg);
|
||||
GPUCMD_AddWrites(GPUREG_VSH_FLOATUNIFORM_DATA+regOffset, data, numreg*4);
|
||||
}
|
||||
|
||||
|
||||
//takes PAs as arguments
|
||||
void GPU_SetViewport(u32* depthBuffer, u32* colorBuffer, u32 x, u32 y, u32 w, u32 h)
|
||||
{
|
||||
u32 param[0x4];
|
||||
float fw=(float)w;
|
||||
float fh=(float)h;
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 0x00000001);
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 0x00000001);
|
||||
|
||||
u32 f116e=0x01000000|(((h-1)&0xFFF)<<12)|(w&0xFFF);
|
||||
|
||||
param[0x0]=((u32)depthBuffer)>>3;
|
||||
param[0x1]=((u32)colorBuffer)>>3;
|
||||
param[0x2]=f116e;
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_DEPTHBUFFER_LOC, param, 0x00000003);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_RENDERBUF_DIM, f116e);
|
||||
GPUCMD_AddWrite(GPUREG_DEPTHBUFFER_FORMAT, 0x00000003); //depth buffer format
|
||||
GPUCMD_AddWrite(GPUREG_COLORBUFFER_FORMAT, 0x00000002); //color buffer format
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_BLOCK32, 0x00000000); //?
|
||||
|
||||
param[0x0]=f32tof24(fw/2);
|
||||
param[0x1]=f32tof31(2.0f / fw) << 1;
|
||||
param[0x2]=f32tof24(fh/2);
|
||||
param[0x3]=f32tof31(2.0f / fh) << 1;
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_VIEWPORT_WIDTH, param, 0x00000004);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_VIEWPORT_XY, (y<<16)|(x&0xFFFF));
|
||||
|
||||
param[0x0]=0x00000000;
|
||||
param[0x1]=0x00000000;
|
||||
param[0x2]=((h-1)<<16)|((w-1)&0xFFFF);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_SCISSORTEST_MODE, param, 0x00000003);
|
||||
|
||||
//enable depth buffer
|
||||
param[0x0]=0x0000000F;
|
||||
param[0x1]=0x0000000F;
|
||||
param[0x2]=0x00000002;
|
||||
param[0x3]=0x00000002;
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_COLORBUFFER_READ, param, 0x00000004);
|
||||
}
|
||||
|
||||
void GPU_SetScissorTest(GPU_SCISSORMODE mode, u32 left, u32 bottom, u32 right, u32 top)
|
||||
{
|
||||
u32 param[3];
|
||||
|
||||
param[0x0] = mode;
|
||||
param[0x1] = (bottom<<16)|(left&0xFFFF);
|
||||
param[0x2] = ((top-1)<<16)|((right-1)&0xFFFF);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_SCISSORTEST_MODE, param, 0x00000003);
|
||||
}
|
||||
|
||||
void GPU_DepthMap(float zScale, float zOffset)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_DEPTHMAP_ENABLE, 0x00000001);
|
||||
GPUCMD_AddWrite(GPUREG_DEPTHMAP_SCALE, f32tof24(zScale));
|
||||
GPUCMD_AddWrite(GPUREG_DEPTHMAP_OFFSET, f32tof24(zOffset));
|
||||
}
|
||||
|
||||
void GPU_SetAlphaTest(bool enable, GPU_TESTFUNC function, u8 ref)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_FRAGOP_ALPHA_TEST, (enable&1)|((function&7)<<4)|(ref<<8));
|
||||
}
|
||||
|
||||
void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref, u8 input_mask, u8 write_mask)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_STENCIL_TEST, (enable&1)|((function&7)<<4)|(write_mask<<8)|(ref<<16)|(input_mask<<24));
|
||||
}
|
||||
|
||||
void GPU_SetStencilOp(GPU_STENCILOP sfail, GPU_STENCILOP dfail, GPU_STENCILOP pass)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_STENCIL_OP, sfail | (dfail << 4) | (pass << 8));
|
||||
}
|
||||
|
||||
void GPU_SetDepthTestAndWriteMask(bool enable, GPU_TESTFUNC function, GPU_WRITEMASK writemask)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_DEPTH_COLOR_MASK, (enable&1)|((function&7)<<4)|(writemask<<8));
|
||||
}
|
||||
|
||||
void GPU_SetAlphaBlending(GPU_BLENDEQUATION colorEquation, GPU_BLENDEQUATION alphaEquation,
|
||||
GPU_BLENDFACTOR colorSrc, GPU_BLENDFACTOR colorDst,
|
||||
GPU_BLENDFACTOR alphaSrc, GPU_BLENDFACTOR alphaDst)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_BLEND_FUNC, colorEquation | (alphaEquation<<8) | (colorSrc<<16) | (colorDst<<20) | (alphaSrc<<24) | (alphaDst<<28));
|
||||
GPUCMD_AddMaskedWrite(GPUREG_COLOR_OPERATION, 0x2, 0x00000100);
|
||||
}
|
||||
|
||||
void GPU_SetColorLogicOp(GPU_LOGICOP op)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_LOGIC_OP, op);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_COLOR_OPERATION, 0x2, 0x00000000);
|
||||
}
|
||||
|
||||
void GPU_SetBlendingColor(u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_BLEND_COLOR, r | (g << 8) | (b << 16) | (a << 24));
|
||||
}
|
||||
|
||||
void GPU_SetTextureEnable(GPU_TEXUNIT units)
|
||||
{
|
||||
GPUCMD_AddMaskedWrite(GPUREG_SH_OUTATTR_CLOCK, 0x2, units<<8); // enables texcoord outputs
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT_CONFIG, 0x00011000|units); // enables texture units
|
||||
}
|
||||
|
||||
void GPU_SetTexture(GPU_TEXUNIT unit, u32* data, u16 width, u16 height, u32 param, GPU_TEXCOLOR colorType)
|
||||
{
|
||||
switch (unit)
|
||||
{
|
||||
case GPU_TEXUNIT0:
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_TYPE, colorType);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_ADDR1, ((u32)data)>>3);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_DIM, (width<<16)|height);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_PARAM, param);
|
||||
break;
|
||||
|
||||
case GPU_TEXUNIT1:
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_TYPE, colorType);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_ADDR, ((u32)data)>>3);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_DIM, (width<<16)|height);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_PARAM, param);
|
||||
break;
|
||||
|
||||
case GPU_TEXUNIT2:
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_TYPE, colorType);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_ADDR, ((u32)data)>>3);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_DIM, (width<<16)|height);
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_PARAM, param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_SetTextureBorderColor(GPU_TEXUNIT unit,u32 borderColor)
|
||||
{
|
||||
switch (unit)
|
||||
{
|
||||
case GPU_TEXUNIT0:
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT0_BORDER_COLOR, borderColor);
|
||||
break;
|
||||
|
||||
case GPU_TEXUNIT1:
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT1_BORDER_COLOR, borderColor);
|
||||
break;
|
||||
|
||||
case GPU_TEXUNIT2:
|
||||
GPUCMD_AddWrite(GPUREG_TEXUNIT2_BORDER_COLOR, borderColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const u8 GPU_FORMATSIZE[4]={1,1,2,4};
|
||||
|
||||
void GPU_SetAttributeBuffers(u8 totalAttributes, u32* baseAddress, u64 attributeFormats, u16 attributeMask, u64 attributePermutation, u8 numBuffers, u32 bufferOffsets[], u64 bufferPermutations[], u8 bufferNumAttributes[])
|
||||
{
|
||||
u32 param[0x28];
|
||||
|
||||
memset(param, 0x00, 0x28*4);
|
||||
|
||||
param[0x0]=((u32)baseAddress)>>3;
|
||||
param[0x1]=attributeFormats&0xFFFFFFFF;
|
||||
param[0x2]=((totalAttributes-1)<<28)|((attributeMask&0xFFF)<<16)|((attributeFormats>>32)&0xFFFF);
|
||||
|
||||
int i, j;
|
||||
u8 sizeTable[0xC];
|
||||
for(i=0;i<totalAttributes;i++)
|
||||
{
|
||||
u8 v=attributeFormats&0xF;
|
||||
sizeTable[i]=GPU_FORMATSIZE[v&3]*((v>>2)+1);
|
||||
attributeFormats>>=4;
|
||||
}
|
||||
|
||||
for(i=0;i<numBuffers;i++)
|
||||
{
|
||||
u16 stride=0;
|
||||
param[3*(i+1)+0]=bufferOffsets[i];
|
||||
param[3*(i+1)+1]=bufferPermutations[i]&0xFFFFFFFF;
|
||||
for(j=0;j<bufferNumAttributes[i];j++)stride+=sizeTable[(bufferPermutations[i]>>(4*j))&0xF];
|
||||
param[3*(i+1)+2]=(bufferNumAttributes[i]<<28)|((stride&0xFFF)<<16)|((bufferPermutations[i]>>32)&0xFFFF);
|
||||
}
|
||||
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_ATTRIBBUFFERS_LOC, param, 0x00000027);
|
||||
|
||||
GPUCMD_AddMaskedWrite(GPUREG_VSH_INPUTBUFFER_CONFIG, 0xB, 0xA0000000|(totalAttributes-1));
|
||||
GPUCMD_AddWrite(GPUREG_VSH_NUM_ATTR, (totalAttributes-1));
|
||||
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW, ((u32[]){attributePermutation&0xFFFFFFFF, (attributePermutation>>32)&0xFFFF}), 2);
|
||||
}
|
||||
|
||||
void GPU_SetAttributeBuffersAddress(u32* baseAddress)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_ATTRIBBUFFERS_LOC, ((u32)baseAddress)>>3);
|
||||
}
|
||||
|
||||
void GPU_SetFaceCulling(GPU_CULLMODE mode)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_FACECULLING_CONFIG, mode&0x3);
|
||||
}
|
||||
|
||||
void GPU_SetCombinerBufferWrite(u8 rgb_config, u8 alpha_config)
|
||||
{
|
||||
GPUCMD_AddMaskedWrite(GPUREG_TEXENV_UPDATE_BUFFER, 0x2, (rgb_config << 8) | (alpha_config << 12));
|
||||
}
|
||||
|
||||
const u8 GPU_TEVID[]={0xC0,0xC8,0xD0,0xD8,0xF0,0xF8};
|
||||
|
||||
void GPU_SetTexEnv(u8 id, u16 rgbSources, u16 alphaSources, u16 rgbOperands, u16 alphaOperands, GPU_COMBINEFUNC rgbCombine, GPU_COMBINEFUNC alphaCombine, u32 constantColor)
|
||||
{
|
||||
if(id>6)return;
|
||||
u32 param[0x5];
|
||||
memset(param, 0x00, 5*4);
|
||||
|
||||
param[0x0]=(alphaSources<<16)|(rgbSources);
|
||||
param[0x1]=(alphaOperands<<12)|(rgbOperands);
|
||||
param[0x2]=(alphaCombine<<16)|(rgbCombine);
|
||||
param[0x3]=constantColor;
|
||||
param[0x4]=0x00000000; // ?
|
||||
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_0000|GPU_TEVID[id], param, 0x00000005);
|
||||
}
|
||||
|
||||
void GPU_DrawArray(GPU_Primitive_t primitive, u32 first, u32 count)
|
||||
{
|
||||
//set primitive type
|
||||
GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 0x2, primitive);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_RESTART_PRIMITIVE, 0x2, 0x00000001);
|
||||
//index buffer address register should be cleared (except bit 31) before drawing
|
||||
GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, 0x80000000);
|
||||
//pass number of vertices
|
||||
GPUCMD_AddWrite(GPUREG_NUMVERTICES, count);
|
||||
//set first vertex
|
||||
GPUCMD_AddWrite(GPUREG_VERTEX_OFFSET, first);
|
||||
|
||||
//all the following except 0x000F022E might be useless
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 0x1, 0x00000001);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 0x1, 0x00000000);
|
||||
GPUCMD_AddWrite(GPUREG_DRAWARRAYS, 0x00000001);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 0x1, 0x00000001);
|
||||
GPUCMD_AddWrite(GPUREG_VTX_FUNC, 0x00000001);
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 0x00000001);
|
||||
}
|
||||
|
||||
void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n)
|
||||
{
|
||||
//set primitive type
|
||||
GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 0x2, primitive);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_RESTART_PRIMITIVE, 0x2, 0x00000001);
|
||||
//index buffer (TODO : support multiple types)
|
||||
GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, 0x80000000|((u32)indexArray));
|
||||
//pass number of vertices
|
||||
GPUCMD_AddWrite(GPUREG_NUMVERTICES, n);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_VERTEX_OFFSET, 0x00000000);
|
||||
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 0x2, 0x00000100);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 0x2, 0x00000100);
|
||||
|
||||
GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 0x1, 0x00000000);
|
||||
GPUCMD_AddWrite(GPUREG_DRAWELEMENTS, 0x00000001);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 0x1, 0x00000001);
|
||||
GPUCMD_AddWrite(GPUREG_VTX_FUNC, 0x00000001);
|
||||
|
||||
// CHECKME: does this one also require GPUREG_FRAMEBUFFER_FLUSH at the end?
|
||||
}
|
||||
|
||||
void GPU_FinishDrawing()
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 0x00000001);
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 0x00000001);
|
||||
GPUCMD_AddWrite(GPUREG_EARLYDEPTH_CLEAR, 0x00000001);
|
||||
}
|
@ -32,7 +32,7 @@ void GPUCMD_GetBuffer(u32** adr, u32* size, u32* offset)
|
||||
if(offset)*offset=gpuCmdBufOffset;
|
||||
}
|
||||
|
||||
void GPUCMD_AddRawCommands(u32* cmd, u32 size)
|
||||
void GPUCMD_AddRawCommands(const u32* cmd, u32 size)
|
||||
{
|
||||
if(!cmd || !size)return;
|
||||
|
||||
@ -55,7 +55,7 @@ void GPUCMD_FlushAndRun(void)
|
||||
GX_ProcessCommandList(gpuCmdBuf, gpuCmdBufOffset*4, 0x0);
|
||||
}
|
||||
|
||||
void GPUCMD_Add(u32 header, u32* param, u32 paramlength)
|
||||
void GPUCMD_Add(u32 header, const u32* param, u32 paramlength)
|
||||
{
|
||||
u32 zero=0x0;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <3ds/gpu/registers.h>
|
||||
#include <3ds/gpu/shaderProgram.h>
|
||||
|
||||
static void GPU_SetShaderOutmap(u32 outmapData[8]);
|
||||
static void GPU_SetShaderOutmap(const u32 outmapData[8]);
|
||||
static void GPU_SendShaderCode(GPU_SHADER_TYPE type, u32* data, u16 offset, u16 length);
|
||||
static void GPU_SendOperandDescriptors(GPU_SHADER_TYPE type, u32* data, u16 offset, u16 length);
|
||||
|
||||
@ -168,7 +168,6 @@ Result shaderProgramSetGsh(shaderProgram_s* sp, DVLE_s* dvle, u8 stride)
|
||||
sp->geoShaderInputPermutation[0] = 0x76543210;
|
||||
sp->geoShaderInputPermutation[1] = 0xFEDCBA98;
|
||||
sp->geoShaderInputStride = stride;
|
||||
sp->geoShaderMode = GSH_NORMAL;
|
||||
|
||||
return shaderInstanceInit(sp->geometryShader, dvle);
|
||||
}
|
||||
@ -182,82 +181,149 @@ Result shaderProgramSetGshInputPermutation(shaderProgram_s* sp, u64 permutation)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result shaderProgramSetGshMode(shaderProgram_s* sp, geoShaderMode mode)
|
||||
static inline void shaderProgramUploadDvle(const DVLE_s* dvle)
|
||||
{
|
||||
if(!sp || !sp->geometryShader)return -1;
|
||||
const DVLP_s* dvlp = dvle->dvlp;
|
||||
// Limit vertex shader code size to the first 512 instructions
|
||||
int codeSize = dvle->type == GEOMETRY_SHDR ? dvlp->codeSize : (dvlp->codeSize < 512 ? dvlp->codeSize : 512);
|
||||
GPU_SendShaderCode(dvle->type, dvlp->codeData, 0, codeSize);
|
||||
GPU_SendOperandDescriptors(dvle->type, dvlp->opcdescData, 0, dvlp->opdescSize);
|
||||
}
|
||||
|
||||
sp->geoShaderMode = mode & 3;
|
||||
return 0;
|
||||
static inline void shaderProgramMergeOutmaps(u32* outmapData, const u32* vshOutmap, const u32* gshOutmap)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
// Find and copy attributes common to both vertex and geometry shader
|
||||
u32 vsh_common = 0, gsh_common = 0;
|
||||
for (i = 1; i < 8; i ++)
|
||||
{
|
||||
u32 mask = gshOutmap[i];
|
||||
if (mask == 0x1F1F1F1F)
|
||||
break;
|
||||
for (j = 1; j < 8; j ++)
|
||||
{
|
||||
if (vshOutmap[j] == mask)
|
||||
{
|
||||
outmapData[++outmapData[0]] = mask;
|
||||
vsh_common |= BIT(j);
|
||||
gsh_common |= BIT(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find and copy attributes that are exclusive to the geometry shader
|
||||
for (i = 1; i < 8; i ++)
|
||||
{
|
||||
u32 mask = gshOutmap[i];
|
||||
if (mask == 0x1F1F1F1F)
|
||||
break;
|
||||
if (!(gsh_common & BIT(i)))
|
||||
outmapData[++outmapData[0]] = mask;
|
||||
}
|
||||
|
||||
// Find and copy attributes that are exclusive to the vertex shader
|
||||
for (i = 1; i < 8; i ++)
|
||||
{
|
||||
u32 mask = vshOutmap[i];
|
||||
if (mask == 0x1F1F1F1F)
|
||||
break;
|
||||
if (!(vsh_common & BIT(i)))
|
||||
outmapData[++outmapData[0]] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
Result shaderProgramConfigure(shaderProgram_s* sp, bool sendVshCode, bool sendGshCode)
|
||||
{
|
||||
if(!sp)return -1;
|
||||
if (!sp || !sp->vertexShader) return -1;
|
||||
|
||||
if(!sp->vertexShader)return -2;
|
||||
|
||||
// configure geostage
|
||||
// has to be done first or else VSH registers might only reconfigure 3 of the 4 shader units !
|
||||
if(!sp->geometryShader)
|
||||
{
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 0x1, 0x00000000);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_VSH_COM_MODE, 0x1, 0x00000000);
|
||||
}else{
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 0x1, 0x00000002);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_VSH_COM_MODE, 0x1, 0x00000001);
|
||||
}
|
||||
|
||||
// setup vertex shader stuff no matter what
|
||||
// Get pointers to relevant structures
|
||||
const DVLE_s* vshDvle = sp->vertexShader->dvle;
|
||||
const DVLP_s* vshDvlp = vshDvle->dvlp;
|
||||
const DVLE_s* gshDvle = sp->geometryShader ? sp->geometryShader->dvle : NULL;
|
||||
const DVLE_s* mainDvle = gshDvle ? gshDvle : vshDvle;
|
||||
|
||||
// Variables for working with the outmap
|
||||
u32 outmapData[8];
|
||||
u32 outmapMode = mainDvle->outmapMode;
|
||||
u32 outmapClock = mainDvle->outmapClock;
|
||||
|
||||
// Initialize geometry engine - do this early in order to ensure all 4 units are correctly initialized
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 0x3, gshDvle ? 2 : 0);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 0x3, 0);
|
||||
GPUCMD_AddMaskedWrite(GPUREG_VSH_COM_MODE, 0x1, gshDvle ? 1 : 0);
|
||||
|
||||
// Set up vertex shader code blob (if necessary)
|
||||
if (sendVshCode)
|
||||
{
|
||||
GPU_SendShaderCode(vshDvle->type, vshDvlp->codeData, 0, vshDvlp->codeSize);
|
||||
GPU_SendOperandDescriptors(vshDvle->type, vshDvlp->opcdescData, 0, vshDvlp->opdescSize);
|
||||
}
|
||||
shaderProgramUploadDvle(vshDvle);
|
||||
|
||||
// Set up vertex shader entrypoint & outmap mask
|
||||
GPUCMD_AddWrite(GPUREG_VSH_ENTRYPOINT, 0x7FFF0000|(vshDvle->mainOffset&0xFFFF));
|
||||
GPUCMD_AddWrite(GPUREG_VSH_OUTMAP_MASK, vshDvle->outmapMask);
|
||||
GPUCMD_AddWrite(GPUREG_VSH_OUTMAP_TOTAL1, vshDvle->outmapData[0]-1);
|
||||
GPUCMD_AddWrite(GPUREG_VSH_OUTMAP_TOTAL2, vshDvle->outmapData[0]-1);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_VSH_OUTMAP_TOTAL1, vshDvle->outmapData[0]-1); // ?
|
||||
GPUCMD_AddWrite(GPUREG_VSH_OUTMAP_TOTAL2, vshDvle->outmapData[0]-1); // ?
|
||||
|
||||
bool subdivision = sp->geoShaderMode >= GSH_SUBDIVISION_LOOP;
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 0x8, subdivision ? 0x80000000 : 0); // Enable or disable subdivision
|
||||
u32 gshMisc = 0;
|
||||
if (subdivision)
|
||||
gshMisc = 1;
|
||||
else if (sp->geoShaderMode == GSH_PARTICLE)
|
||||
gshMisc = 0x01004302;
|
||||
GPUCMD_AddWrite(GPUREG_GSH_MISC0, gshMisc);
|
||||
GPUCMD_AddWrite(GPUREG_GSH_MISC1, sp->geoShaderMode);
|
||||
|
||||
if(!sp->geometryShader)
|
||||
// Set up geometry shader (if present)
|
||||
if (gshDvle)
|
||||
{
|
||||
// finish setting up vertex shader alone
|
||||
GPU_SetShaderOutmap((u32*)vshDvle->outmapData);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_SH_OUTATTR_MODE, vshDvle->outmapMode);
|
||||
GPUCMD_AddWrite(GPUREG_SH_OUTATTR_CLOCK, vshDvle->outmapClock);
|
||||
}else{
|
||||
// setup both vertex and geometry shader
|
||||
const DVLE_s* gshDvle = sp->geometryShader->dvle;
|
||||
const DVLP_s* gshDvlp = gshDvle->dvlp;
|
||||
// Set up geometry shader code blob (if necessary)
|
||||
if (sendGshCode)
|
||||
{
|
||||
GPU_SendShaderCode(gshDvle->type, gshDvlp->codeData, 0, gshDvlp->codeSize);
|
||||
GPU_SendOperandDescriptors(gshDvle->type, gshDvlp->opcdescData, 0, gshDvlp->opdescSize);
|
||||
}
|
||||
shaderProgramUploadDvle(gshDvle);
|
||||
|
||||
// Set up geometry shader entrypoint & outmap mask
|
||||
GPUCMD_AddWrite(GPUREG_GSH_ENTRYPOINT, 0x7FFF0000|(gshDvle->mainOffset&0xFFFF));
|
||||
GPUCMD_AddWrite(GPUREG_GSH_OUTMAP_MASK, gshDvle->outmapMask);
|
||||
}
|
||||
|
||||
GPU_SetShaderOutmap((u32*)gshDvle->outmapData);
|
||||
// Merge vertex shader & geometry shader outmaps if requested
|
||||
if (gshDvle && gshDvle->mergeOutmaps)
|
||||
{
|
||||
// Clear outmap
|
||||
memset(outmapData, 0x1F, sizeof(outmapData));
|
||||
outmapData[0] = 0;
|
||||
|
||||
//GSH input attributes stuff
|
||||
GPUCMD_AddWrite(GPUREG_GSH_INPUTBUFFER_CONFIG, 0x08000000|(sp->geoShaderInputStride-1)|(subdivision?0x100:0));
|
||||
// Merge outmaps
|
||||
shaderProgramMergeOutmaps(outmapData, vshDvle->outmapData, gshDvle->outmapData);
|
||||
outmapMode |= vshDvle->outmapMode;
|
||||
outmapClock |= vshDvle->outmapClock;
|
||||
} else
|
||||
memcpy(outmapData, mainDvle->outmapData, sizeof(outmapData));
|
||||
|
||||
// Upload and configure outmap
|
||||
GPU_SetShaderOutmap(outmapData);
|
||||
GPUCMD_AddWrite(GPUREG_SH_OUTATTR_MODE, outmapMode);
|
||||
GPUCMD_AddWrite(GPUREG_SH_OUTATTR_CLOCK, outmapClock);
|
||||
|
||||
// Configure geostage
|
||||
if (gshDvle)
|
||||
{
|
||||
// Input stride: use value if specified, otherwise use number of outputs in vertex shader
|
||||
int stride = sp->geoShaderInputStride ? sp->geoShaderInputStride : vshDvle->outmapData[0];
|
||||
|
||||
// Enable or disable variable-size primitive processing
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 0xA, gshDvle->gshMode == GSH_VARIABLE_PRIM ? 0x80000000 : 0);
|
||||
|
||||
// Set up geoshader processing mode
|
||||
u32 misc = gshDvle->gshMode;
|
||||
if (misc == GSH_FIXED_PRIM)
|
||||
misc |= 0x01000000 | ((u32)gshDvle->gshFixedVtxStart<<16) | ((stride-1)<<12) | ((u32)(gshDvle->gshFixedVtxNum-1)<<8);
|
||||
GPUCMD_AddWrite(GPUREG_GSH_MISC0, misc);
|
||||
|
||||
// Set up variable-size primitive mode parameters
|
||||
GPUCMD_AddWrite(GPUREG_GSH_MISC1, gshDvle->gshMode == GSH_VARIABLE_PRIM ? (gshDvle->gshVariableVtxNum-1) : 0);
|
||||
|
||||
// Set up geoshader input
|
||||
GPUCMD_AddWrite(GPUREG_GSH_INPUTBUFFER_CONFIG, 0x08000000 | (gshDvle->gshMode ? 0x0100 : 0) | (stride-1));
|
||||
|
||||
// Set up geoshader permutation
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW, sp->geoShaderInputPermutation, 2);
|
||||
|
||||
GPUCMD_AddWrite(GPUREG_SH_OUTATTR_MODE, gshDvle->outmapMode);
|
||||
GPUCMD_AddWrite(GPUREG_SH_OUTATTR_CLOCK, gshDvle->outmapClock);
|
||||
} else
|
||||
{
|
||||
// Defaults for when geostage is disabled
|
||||
GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 0xA, 0);
|
||||
GPUCMD_AddWrite(GPUREG_GSH_MISC0, 0);
|
||||
GPUCMD_AddWrite(GPUREG_GSH_MISC1, 0);
|
||||
GPUCMD_AddWrite(GPUREG_GSH_INPUTBUFFER_CONFIG, 0xA0000000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -271,12 +337,12 @@ Result shaderProgramUse(shaderProgram_s* sp)
|
||||
int i;
|
||||
|
||||
// Set up uniforms
|
||||
GPUCMD_AddWrite(GPUREG_VSH_BOOLUNIFORM, 0x7FFF0000|~sp->vertexShader->boolUniforms);
|
||||
GPUCMD_AddWrite(GPUREG_VSH_BOOLUNIFORM, 0x7FFF0000|sp->vertexShader->boolUniforms);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_VSH_INTUNIFORM_I0, sp->vertexShader->intUniforms, 4);
|
||||
for(i=0; i<sp->vertexShader->numFloat24Uniforms; i++) GPUCMD_AddIncrementalWrites(GPUREG_VSH_FLOATUNIFORM_CONFIG, (u32*)&sp->vertexShader->float24Uniforms[i], 4);
|
||||
if (sp->geometryShader)
|
||||
{
|
||||
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0x7FFF0000|~sp->geometryShader->boolUniforms);
|
||||
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0x7FFF0000|sp->geometryShader->boolUniforms);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_GSH_INTUNIFORM_I0, sp->geometryShader->intUniforms, 4);
|
||||
for(i=0; i<sp->geometryShader->numFloat24Uniforms; i++) GPUCMD_AddIncrementalWrites(GPUREG_GSH_FLOATUNIFORM_CONFIG, (u32*)&sp->geometryShader->float24Uniforms[i], 4);
|
||||
}
|
||||
@ -284,7 +350,7 @@ Result shaderProgramUse(shaderProgram_s* sp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GPU_SetShaderOutmap(u32 outmapData[8])
|
||||
void GPU_SetShaderOutmap(const u32 outmapData[8])
|
||||
{
|
||||
GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 0x1, outmapData[0]-1);
|
||||
GPUCMD_AddIncrementalWrites(GPUREG_SH_OUTMAP_TOTAL, outmapData, 8);
|
||||
|
@ -38,9 +38,18 @@ DVLB_s* DVLB_ParseFile(u32* shbinData, u32 shbinSize)
|
||||
dvle->dvlp=&ret->DVLP;
|
||||
|
||||
dvle->type=(dvleData[1]>>16)&0xFF;
|
||||
dvle->mergeOutmaps=(dvleData[1]>>24)&1;
|
||||
dvle->mainOffset=dvleData[2];
|
||||
dvle->endmainOffset=dvleData[3];
|
||||
|
||||
if(dvle->type==GEOMETRY_SHDR)
|
||||
{
|
||||
dvle->gshMode=dvleData[5]&0xFF;
|
||||
dvle->gshFixedVtxStart=(dvleData[5]>>8)&0xFF;
|
||||
dvle->gshVariableVtxNum=(dvleData[5]>>16)&0xFF;
|
||||
dvle->gshFixedVtxNum=(dvleData[5]>>24)&0xFF;
|
||||
}
|
||||
|
||||
dvle->constTableSize=dvleData[7];
|
||||
dvle->constTableData=(DVLE_constEntry_s*)&dvleData[dvleData[6]/4];
|
||||
|
||||
@ -89,80 +98,53 @@ s8 DVLE_GetUniformRegister(DVLE_s* dvle, const char* name)
|
||||
|
||||
void DVLE_GenerateOutmap(DVLE_s* dvle)
|
||||
{
|
||||
if(!dvle)return;
|
||||
if (!dvle) return;
|
||||
|
||||
// Initialize outmap data
|
||||
memset(dvle->outmapData, 0x1F, sizeof(dvle->outmapData));
|
||||
dvle->outmapData[0] = 0;
|
||||
dvle->outmapMask = 0;
|
||||
dvle->outmapMode = 0;
|
||||
dvle->outmapClock = 0;
|
||||
|
||||
int i;
|
||||
u8 numAttr=0;
|
||||
u8 maxAttr=0;
|
||||
u8 attrMask=0;
|
||||
u32 attrMode=0;
|
||||
u32 attrClock=0;
|
||||
|
||||
for(i=0;i<dvle->outTableSize;i++)
|
||||
int i, j, k;
|
||||
for (i = 0; i < dvle->outTableSize; i ++)
|
||||
{
|
||||
u32* out=&dvle->outmapData[dvle->outTableData[i].regID+1];
|
||||
u32 mask=0x00000000;
|
||||
u8 tmpmask=dvle->outTableData[i].mask;
|
||||
mask=(mask<<8)|((tmpmask&8)?0xFF:0x00);tmpmask<<=1;
|
||||
mask=(mask<<8)|((tmpmask&8)?0xFF:0x00);tmpmask<<=1;
|
||||
mask=(mask<<8)|((tmpmask&8)?0xFF:0x00);tmpmask<<=1;
|
||||
mask=(mask<<8)|((tmpmask&8)?0xFF:0x00);tmpmask<<=1;
|
||||
int type = dvle->outTableData[i].type;
|
||||
int mask = dvle->outTableData[i].mask;
|
||||
int regID = dvle->outTableData[i].regID;
|
||||
u32* out = &dvle->outmapData[regID+1];
|
||||
|
||||
if(*out==0x1F1F1F1F)numAttr++;
|
||||
|
||||
u32 val=0x1F1F1F1F;
|
||||
switch(dvle->outTableData[i].type)
|
||||
if (!(dvle->outmapMask & BIT(regID)))
|
||||
{
|
||||
case RESULT_POSITION: val=0x03020100; break;
|
||||
case RESULT_NORMALQUAT: val=0x07060504; break;
|
||||
case RESULT_COLOR: val=0x0B0A0908; break;
|
||||
case RESULT_TEXCOORD0: val=0x1F1F0D0C; break;
|
||||
case RESULT_TEXCOORD0W: val=0x10101010; break;
|
||||
case RESULT_TEXCOORD1: val=0x1F1F0F0E; break;
|
||||
case RESULT_TEXCOORD2: val=0x1F1F1716; break;
|
||||
case RESULT_VIEW: val=0x1F141312; break;
|
||||
}
|
||||
*out=((*out)&~mask)|(val&mask);
|
||||
|
||||
switch(dvle->outTableData[i].type)
|
||||
{
|
||||
case RESULT_POSITION:
|
||||
if ((*out & 0xFF0000)==0x020000)
|
||||
attrClock |= BIT(0);
|
||||
break;
|
||||
case RESULT_COLOR:
|
||||
attrClock |= BIT(1);
|
||||
break;
|
||||
case RESULT_TEXCOORD0:
|
||||
attrMode = 1;
|
||||
attrClock |= BIT(8);
|
||||
break;
|
||||
case RESULT_TEXCOORD1:
|
||||
attrMode = 1;
|
||||
attrClock |= BIT(9);
|
||||
break;
|
||||
case RESULT_TEXCOORD2:
|
||||
attrMode = 1;
|
||||
attrClock |= BIT(10);
|
||||
break;
|
||||
case RESULT_TEXCOORD0W:
|
||||
attrMode = 1;
|
||||
attrClock |= BIT(16);
|
||||
break;
|
||||
case RESULT_NORMALQUAT:
|
||||
case RESULT_VIEW:
|
||||
attrClock |= BIT(24);
|
||||
break;
|
||||
dvle->outmapMask |= BIT(regID);
|
||||
dvle->outmapData[0] ++;
|
||||
}
|
||||
|
||||
attrMask|=1<<dvle->outTableData[i].regID;
|
||||
if(dvle->outTableData[i].regID+1>maxAttr)maxAttr=dvle->outTableData[i].regID+1;
|
||||
int sem = 0x1F, num = 0;
|
||||
switch (type)
|
||||
{
|
||||
case RESULT_POSITION: sem = 0x00; num = 4; break;
|
||||
case RESULT_NORMALQUAT: sem = 0x04; num = 4; dvle->outmapClock |= BIT(24); break;
|
||||
case RESULT_COLOR: sem = 0x08; num = 4; dvle->outmapClock |= BIT(1); break;
|
||||
case RESULT_TEXCOORD0: sem = 0x0C; num = 2; dvle->outmapClock |= BIT(8); dvle->outmapMode = 1; break;
|
||||
case RESULT_TEXCOORD0W: sem = 0x10; num = 1; dvle->outmapClock |= BIT(16); dvle->outmapMode = 1; break;
|
||||
case RESULT_TEXCOORD1: sem = 0x0E; num = 2; dvle->outmapClock |= BIT(9); dvle->outmapMode = 1; break;
|
||||
case RESULT_TEXCOORD2: sem = 0x16; num = 2; dvle->outmapClock |= BIT(10); dvle->outmapMode = 1; break;
|
||||
case RESULT_VIEW: sem = 0x12; num = 3; dvle->outmapClock |= BIT(24); break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
for (j = 0, k = 0; j < 4 && k < num; j ++)
|
||||
{
|
||||
if (mask & BIT(j))
|
||||
{
|
||||
*out &= ~(0xFF << (j*8));
|
||||
*out |= (sem++) << (j*8);
|
||||
k ++;
|
||||
if (type==RESULT_POSITION && k==3)
|
||||
dvle->outmapClock |= BIT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dvle->outmapData[0]=numAttr;
|
||||
dvle->outmapMask=attrMask;
|
||||
dvle->outmapMode=attrMode;
|
||||
dvle->outmapClock=attrClock;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
u16 ndspFrameId, ndspBufferCurId, ndspBufferId;
|
||||
void* ndspVars[16][2];
|
||||
|
||||
static bool bComponentLoaded = false, bDspReady = false, bSleeping = false, bNeedsSync = false;
|
||||
static bool bComponentLoaded = false, bDspReady = false, bSleeping = false, bActuallySleeping = false, bNeedsSync = false;
|
||||
static u32 droppedFrames, frameCount;
|
||||
|
||||
static const void* componentBin;
|
||||
@ -19,7 +19,8 @@ static bool componentFree;
|
||||
|
||||
static aptHookCookie aptCookie;
|
||||
|
||||
static Handle irqEvent, dspSem, sleepEvent;
|
||||
static Handle irqEvent, dspSem;
|
||||
static LightEvent sleepEvent;
|
||||
static LightLock ndspMutex;
|
||||
|
||||
static u8 dspVar5Backup[0x1080];
|
||||
@ -211,7 +212,7 @@ static Result ndspInitialize(bool resume)
|
||||
rc = ndspLoadComponent();
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
rc = svcCreateEvent(&irqEvent, 1);
|
||||
rc = svcCreateEvent(&irqEvent, RESET_STICKY);
|
||||
if (R_FAILED(rc)) goto _fail1;
|
||||
|
||||
rc = DSP_RegisterInterruptEvents(irqEvent, 2, 2);
|
||||
@ -305,7 +306,11 @@ static void ndspAptHook(APT_HookType hook, void* param)
|
||||
case APTHOOK_ONWAKEUP:
|
||||
bSleeping = false;
|
||||
ndspInitialize(true);
|
||||
svcSignalEvent(sleepEvent);
|
||||
if (bActuallySleeping)
|
||||
{
|
||||
bActuallySleeping = false;
|
||||
LightEvent_Signal(&sleepEvent);
|
||||
}
|
||||
break;
|
||||
|
||||
case APTHOOK_ONSUSPEND:
|
||||
@ -323,8 +328,8 @@ static void ndspSync(void)
|
||||
{
|
||||
if (bSleeping)
|
||||
{
|
||||
svcWaitSynchronization(sleepEvent, U64_MAX);
|
||||
svcClearEvent(sleepEvent);
|
||||
bActuallySleeping = true;
|
||||
LightEvent_Wait(&sleepEvent);
|
||||
}
|
||||
|
||||
ndspWaitForIrq();
|
||||
@ -455,7 +460,7 @@ Result ndspInit(void)
|
||||
|
||||
if (!componentBin && !ndspFindAndLoadComponent())
|
||||
{
|
||||
rc = MAKERESULT(RL_PERMANENT, RS_NOTFOUND, 41, RD_NOT_FOUND);
|
||||
rc = MAKERESULT(RL_PERMANENT, RS_NOTFOUND, RM_DSP, RD_NOT_FOUND);
|
||||
goto _fail0;
|
||||
}
|
||||
|
||||
@ -479,17 +484,14 @@ Result ndspInit(void)
|
||||
rc = ndspInitialize(false);
|
||||
if (R_FAILED(rc)) goto _fail1;
|
||||
|
||||
rc = svcCreateEvent(&sleepEvent, 0);
|
||||
if (R_FAILED(rc)) goto _fail2;
|
||||
LightEvent_Init(&sleepEvent, RESET_ONESHOT);
|
||||
|
||||
ndspThread = threadCreate(ndspThreadMain, 0x0, NDSP_THREAD_STACK_SIZE, 0x18, -2, true);
|
||||
if (!ndspThread) goto _fail3;
|
||||
if (!ndspThread) goto _fail2;
|
||||
|
||||
aptHook(&aptCookie, ndspAptHook, NULL);
|
||||
return 0;
|
||||
|
||||
_fail3:
|
||||
svcCloseHandle(sleepEvent);
|
||||
_fail2:
|
||||
ndspFinalize(false);
|
||||
_fail1:
|
||||
@ -509,10 +511,12 @@ void ndspExit(void)
|
||||
if (AtomicDecrement(&ndspRefCount)) return;
|
||||
if (!bDspReady) return;
|
||||
ndspThreadRun = false;
|
||||
if (bSleeping)
|
||||
svcSignalEvent(sleepEvent);
|
||||
if (bActuallySleeping)
|
||||
{
|
||||
bActuallySleeping = false;
|
||||
LightEvent_Signal(&sleepEvent);
|
||||
}
|
||||
threadJoin(ndspThread, U64_MAX);
|
||||
svcCloseHandle(sleepEvent);
|
||||
aptUnhook(&aptCookie);
|
||||
if (!bSleeping)
|
||||
ndspFinalize(false);
|
||||
|
@ -41,11 +41,12 @@ static Result __read_versionbin(FS_ArchiveID archiveId, FS_Path archivePath, FS_
|
||||
Result ret = 0;
|
||||
Handle filehandle = 0;
|
||||
FILE *f = NULL;
|
||||
struct romfs_mount *mount;
|
||||
|
||||
ret = FSUSER_OpenFileDirectly(&filehandle, archiveId, archivePath, fileLowPath, FS_OPEN_READ, 0x0);
|
||||
if(R_FAILED(ret))return ret;
|
||||
|
||||
ret = romfsInitFromFile(filehandle, 0x0);
|
||||
ret = romfsMountFromFile(filehandle, 0x0, &mount);
|
||||
if(R_FAILED(ret))return ret;
|
||||
|
||||
f = fopen("romfs:/version.bin", "r");
|
||||
@ -59,7 +60,7 @@ static Result __read_versionbin(FS_ArchiveID archiveId, FS_Path archivePath, FS_
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
romfsExit();
|
||||
romfsUnmount(mount);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -16,15 +16,17 @@
|
||||
#include <3ds/util/utf.h>
|
||||
#include <3ds/env.h>
|
||||
|
||||
static bool romFS_active;
|
||||
static Handle romFS_file;
|
||||
static time_t romFS_mtime;
|
||||
static u32 romFS_offset;
|
||||
static romfs_header romFS_header;
|
||||
static romfs_dir* romFS_cwd;
|
||||
|
||||
static u32 *dirHashTable, *fileHashTable;
|
||||
static void *dirTable, *fileTable;
|
||||
typedef struct romfs_mount
|
||||
{
|
||||
Handle fd;
|
||||
time_t mtime;
|
||||
u32 offset;
|
||||
romfs_header header;
|
||||
romfs_dir *cwd;
|
||||
u32 *dirHashTable, *fileHashTable;
|
||||
void *dirTable, *fileTable;
|
||||
struct romfs_mount *next;
|
||||
} romfs_mount;
|
||||
|
||||
extern int __system_argc;
|
||||
extern char** __system_argv;
|
||||
@ -32,25 +34,25 @@ extern char** __system_argv;
|
||||
static char __component[PATH_MAX+1];
|
||||
static uint16_t __utf16path[PATH_MAX+1];
|
||||
|
||||
#define romFS_root ((romfs_dir*)dirTable)
|
||||
#define romFS_dir(x) ((romfs_dir*) ((u8*)dirTable + (x)))
|
||||
#define romFS_file(x) ((romfs_file*)((u8*)fileTable + (x)))
|
||||
#define romFS_root(m) ((romfs_dir*)(m)->dirTable)
|
||||
#define romFS_dir(m,x) ((romfs_dir*) ((u8*)(m)->dirTable + (x)))
|
||||
#define romFS_file(m,x) ((romfs_file*)((u8*)(m)->fileTable + (x)))
|
||||
#define romFS_none ((u32)~0)
|
||||
#define romFS_dir_mode (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH)
|
||||
#define romFS_file_mode (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH)
|
||||
|
||||
static ssize_t _romfs_read(u64 offset, void* buffer, u32 size)
|
||||
static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u32 size)
|
||||
{
|
||||
u64 pos = (u64)romFS_offset + offset;
|
||||
u64 pos = (u64)mount->offset + offset;
|
||||
u32 read = 0;
|
||||
Result rc = FSFILE_Read(romFS_file, &read, pos, buffer, size);
|
||||
Result rc = FSFILE_Read(mount->fd, &read, pos, buffer, size);
|
||||
if (R_FAILED(rc)) return -1;
|
||||
return read;
|
||||
}
|
||||
|
||||
static bool _romfs_read_chk(u64 offset, void* buffer, u32 size)
|
||||
static bool _romfs_read_chk(romfs_mount *mount, u64 offset, void* buffer, u32 size)
|
||||
{
|
||||
return _romfs_read(offset, buffer, size) == size;
|
||||
return _romfs_read(mount, offset, buffer, size) == size;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -69,12 +71,14 @@ static int romfs_dirclose(struct _reent *r, DIR_ITER *dirState);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
romfs_file *file;
|
||||
u64 offset, pos;
|
||||
romfs_mount *mount;
|
||||
romfs_file *file;
|
||||
u64 offset, pos;
|
||||
} romfs_fileobj;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
romfs_mount *mount;
|
||||
romfs_dir* dir;
|
||||
u32 state;
|
||||
u32 childDir;
|
||||
@ -120,21 +124,68 @@ typedef struct
|
||||
u32 fsOffset;
|
||||
} _3DSX_Header;
|
||||
|
||||
static Result romfsInitCommon(void);
|
||||
static void romfsInitMtime(FS_ArchiveID archId, FS_Path archPath, FS_Path filePath);
|
||||
static Result romfsMountCommon(romfs_mount *mount);
|
||||
static void romfsInitMtime(romfs_mount *mount, FS_ArchiveID archId, FS_Path archPath, FS_Path filePath);
|
||||
|
||||
__attribute__((weak)) const char* __romfs_path = NULL;
|
||||
|
||||
Result romfsInit(void)
|
||||
static romfs_mount *romfs_mount_list = NULL;
|
||||
|
||||
static void romfs_insert(romfs_mount *mount)
|
||||
{
|
||||
if (romFS_active) return 0;
|
||||
mount->next = romfs_mount_list;
|
||||
romfs_mount_list = mount;
|
||||
}
|
||||
|
||||
static void romfs_remove(romfs_mount *mount)
|
||||
{
|
||||
for(romfs_mount **it = &romfs_mount_list; *it; it = &(*it)->next)
|
||||
{
|
||||
if(*it == mount)
|
||||
{
|
||||
*it = mount->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static romfs_mount* romfs_alloc(void)
|
||||
{
|
||||
romfs_mount *mount = (romfs_mount*)calloc(1, sizeof(romfs_mount));
|
||||
|
||||
if(mount)
|
||||
romfs_insert(mount);
|
||||
|
||||
return mount;
|
||||
}
|
||||
|
||||
static void romfs_free(romfs_mount *mount)
|
||||
{
|
||||
romfs_remove(mount);
|
||||
free(mount->fileTable);
|
||||
free(mount->fileHashTable);
|
||||
free(mount->dirTable);
|
||||
free(mount->dirHashTable);
|
||||
free(mount);
|
||||
}
|
||||
|
||||
Result romfsMount(struct romfs_mount **p)
|
||||
{
|
||||
romfs_mount *mount = romfs_alloc();
|
||||
if(mount == NULL)
|
||||
return 99;
|
||||
|
||||
if (envIsHomebrew())
|
||||
{
|
||||
// RomFS appended to a 3DSX file
|
||||
const char* filename = __romfs_path;
|
||||
if (__system_argc > 0 && __system_argv[0])
|
||||
filename = __system_argv[0];
|
||||
if (!filename) return 1;
|
||||
if (!filename)
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strncmp(filename, "sdmc:/", 6) == 0)
|
||||
filename += 5;
|
||||
@ -144,29 +195,46 @@ Result romfsInit(void)
|
||||
strncat(__component, filename+8, PATH_MAX);
|
||||
__component[PATH_MAX] = 0;
|
||||
filename = __component;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 2;
|
||||
}
|
||||
|
||||
ssize_t units = utf8_to_utf16(__utf16path, (const uint8_t*)filename, PATH_MAX);
|
||||
if (units < 0) return 3;
|
||||
if (units >= PATH_MAX) return 4;
|
||||
if (units < 0)
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 3;
|
||||
}
|
||||
if (units >= PATH_MAX)
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 4;
|
||||
}
|
||||
__utf16path[units] = 0;
|
||||
|
||||
FS_Path archPath = { PATH_EMPTY, 1, (u8*)"" };
|
||||
FS_Path filePath = { PATH_UTF16, (units+1)*2, (u8*)__utf16path };
|
||||
|
||||
Result rc = FSUSER_OpenFileDirectly(&romFS_file, ARCHIVE_SDMC, archPath, filePath, FS_OPEN_READ, 0);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
Result rc = FSUSER_OpenFileDirectly(&mount->fd, ARCHIVE_SDMC, archPath, filePath, FS_OPEN_READ, 0);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
romfs_free(mount);
|
||||
return rc;
|
||||
}
|
||||
|
||||
romfsInitMtime(ARCHIVE_SDMC, archPath, filePath);
|
||||
romfsInitMtime(mount, ARCHIVE_SDMC, archPath, filePath);
|
||||
|
||||
_3DSX_Header hdr;
|
||||
if (!_romfs_read_chk(0, &hdr, sizeof(hdr))) goto _fail0;
|
||||
if (!_romfs_read_chk(mount, 0, &hdr, sizeof(hdr))) goto _fail0;
|
||||
if (hdr.magic != _3DSX_MAGIC) goto _fail0;
|
||||
if (hdr.headerSize < sizeof(hdr)) goto _fail0;
|
||||
romFS_offset = hdr.fsOffset;
|
||||
if (!romFS_offset) goto _fail0;
|
||||
} else
|
||||
mount->offset = hdr.fsOffset;
|
||||
if (!mount->offset) goto _fail0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Regular RomFS
|
||||
u8 zeros[0xC];
|
||||
@ -175,75 +243,94 @@ Result romfsInit(void)
|
||||
FS_Path archPath = { PATH_EMPTY, 1, (u8*)"" };
|
||||
FS_Path filePath = { PATH_BINARY, sizeof(zeros), zeros };
|
||||
|
||||
Result rc = FSUSER_OpenFileDirectly(&romFS_file, ARCHIVE_ROMFS, archPath, filePath, FS_OPEN_READ, 0);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
Result rc = FSUSER_OpenFileDirectly(&mount->fd, ARCHIVE_ROMFS, archPath, filePath, FS_OPEN_READ, 0);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
romfs_free(mount);
|
||||
return rc;
|
||||
}
|
||||
|
||||
romfsInitMtime(ARCHIVE_ROMFS, archPath, filePath);
|
||||
romfsInitMtime(mount, ARCHIVE_ROMFS, archPath, filePath);
|
||||
}
|
||||
|
||||
return romfsInitCommon();
|
||||
Result ret = romfsMountCommon(mount);
|
||||
if(R_SUCCEEDED(ret) && p)
|
||||
*p = mount;
|
||||
|
||||
return ret;
|
||||
|
||||
_fail0:
|
||||
FSFILE_Close(romFS_file);
|
||||
FSFILE_Close(mount->fd);
|
||||
romfs_free(mount);
|
||||
return 10;
|
||||
}
|
||||
|
||||
Result romfsInitFromFile(Handle file, u32 offset)
|
||||
Result romfsMountFromFile(Handle file, u32 offset, struct romfs_mount **p)
|
||||
{
|
||||
if (romFS_active) return 0;
|
||||
romFS_file = file;
|
||||
romFS_offset = offset;
|
||||
return romfsInitCommon();
|
||||
romfs_mount *mount = romfs_alloc();
|
||||
if(mount == NULL)
|
||||
return 99;
|
||||
|
||||
mount->fd = file;
|
||||
mount->offset = offset;
|
||||
|
||||
Result ret = romfsMountCommon(mount);
|
||||
if(R_SUCCEEDED(ret) && p)
|
||||
*p = mount;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result romfsInitCommon(void)
|
||||
Result romfsMountCommon(romfs_mount *mount)
|
||||
{
|
||||
if (_romfs_read(0, &romFS_header, sizeof(romFS_header)) != sizeof(romFS_header))
|
||||
goto _fail0;
|
||||
if (_romfs_read(mount, 0, &mount->header, sizeof(mount->header)) != sizeof(mount->header))
|
||||
goto fail;
|
||||
|
||||
dirHashTable = (u32*)malloc(romFS_header.dirHashTableSize);
|
||||
if (!dirHashTable) goto _fail0;
|
||||
if (!_romfs_read_chk(romFS_header.dirHashTableOff, dirHashTable, romFS_header.dirHashTableSize)) goto _fail1;
|
||||
mount->dirHashTable = (u32*)malloc(mount->header.dirHashTableSize);
|
||||
if (!mount->dirHashTable)
|
||||
goto fail;
|
||||
if (!_romfs_read_chk(mount, mount->header.dirHashTableOff, mount->dirHashTable, mount->header.dirHashTableSize))
|
||||
goto fail;
|
||||
|
||||
dirTable = malloc(romFS_header.dirTableSize);
|
||||
if (!dirTable) goto _fail1;
|
||||
if (!_romfs_read_chk(romFS_header.dirTableOff, dirTable, romFS_header.dirTableSize)) goto _fail2;
|
||||
mount->dirTable = malloc(mount->header.dirTableSize);
|
||||
if (!mount->dirTable)
|
||||
goto fail;
|
||||
if (!_romfs_read_chk(mount, mount->header.dirTableOff, mount->dirTable, mount->header.dirTableSize))
|
||||
goto fail;
|
||||
|
||||
fileHashTable = (u32*)malloc(romFS_header.fileHashTableSize);
|
||||
if (!fileHashTable) goto _fail2;
|
||||
if (!_romfs_read_chk(romFS_header.fileHashTableOff, fileHashTable, romFS_header.fileHashTableSize)) goto _fail3;
|
||||
mount->fileHashTable = (u32*)malloc(mount->header.fileHashTableSize);
|
||||
if (!mount->fileHashTable)
|
||||
goto fail;
|
||||
if (!_romfs_read_chk(mount, mount->header.fileHashTableOff, mount->fileHashTable, mount->header.fileHashTableSize))
|
||||
goto fail;
|
||||
|
||||
fileTable = malloc(romFS_header.fileTableSize);
|
||||
if (!fileTable) goto _fail3;
|
||||
if (!_romfs_read_chk(romFS_header.fileTableOff, fileTable, romFS_header.fileTableSize)) goto _fail4;
|
||||
mount->fileTable = malloc(mount->header.fileTableSize);
|
||||
if (!mount->fileTable)
|
||||
goto fail;
|
||||
if (!_romfs_read_chk(mount, mount->header.fileTableOff, mount->fileTable, mount->header.fileTableSize))
|
||||
goto fail;
|
||||
|
||||
romFS_cwd = romFS_root;
|
||||
romFS_active = true;
|
||||
mount->cwd = romFS_root(mount);
|
||||
|
||||
AddDevice(&romFS_devoptab);
|
||||
// add device if this is the first one
|
||||
if(mount->next == NULL && AddDevice(&romFS_devoptab) < 0)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
_fail4:
|
||||
free(fileTable);
|
||||
_fail3:
|
||||
free(fileHashTable);
|
||||
_fail2:
|
||||
free(dirTable);
|
||||
_fail1:
|
||||
free(dirHashTable);
|
||||
_fail0:
|
||||
FSFILE_Close(romFS_file);
|
||||
fail:
|
||||
FSFILE_Close(mount->fd);
|
||||
romfs_free(mount);
|
||||
return 10;
|
||||
}
|
||||
|
||||
static void romfsInitMtime(FS_ArchiveID archId, FS_Path archPath, FS_Path filePath)
|
||||
static void romfsInitMtime(romfs_mount *mount, FS_ArchiveID archId, FS_Path archPath, FS_Path filePath)
|
||||
{
|
||||
u64 mtime;
|
||||
FS_Archive arch;
|
||||
Result rc;
|
||||
|
||||
romFS_mtime = time(NULL);
|
||||
mount->mtime = time(NULL);
|
||||
rc = FSUSER_OpenArchive(&arch, archId, archPath);
|
||||
if (R_FAILED(rc))
|
||||
return;
|
||||
@ -259,21 +346,45 @@ static void romfsInitMtime(FS_ArchiveID archId, FS_Path archPath, FS_Path filePa
|
||||
mtime /= 1000;
|
||||
/* convert from 2000-based timestamp to UNIX timestamp */
|
||||
mtime += 946684800;
|
||||
romFS_mtime = mtime;
|
||||
mount->mtime = mtime;
|
||||
}
|
||||
|
||||
Result romfsExit(void)
|
||||
Result romfsBind(struct romfs_mount *mount)
|
||||
{
|
||||
if (!romFS_active) return 0;
|
||||
romFS_active = false;
|
||||
for(romfs_mount **it = &romfs_mount_list; *it; it = &(*it)->next)
|
||||
{
|
||||
if(*it == mount)
|
||||
{
|
||||
*it = mount->next;
|
||||
romfs_insert(mount);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
RemoveDevice("romfs:");
|
||||
FSFILE_Close(romFS_file);
|
||||
free(dirHashTable);
|
||||
free(fileHashTable);
|
||||
free(dirTable);
|
||||
free(fileTable);
|
||||
romFS_offset = 0;
|
||||
return 99;
|
||||
}
|
||||
|
||||
Result romfsUnmount(struct romfs_mount *mount)
|
||||
{
|
||||
if(mount)
|
||||
{
|
||||
// unmount specific
|
||||
FSFILE_Close(mount->fd);
|
||||
romfs_free(mount);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unmount everything
|
||||
while(romfs_mount_list)
|
||||
{
|
||||
FSFILE_Close(romfs_mount_list->fd);
|
||||
romfs_free(romfs_mount_list);
|
||||
}
|
||||
}
|
||||
|
||||
// if no more mounts, remove device
|
||||
if(romfs_mount_list == NULL)
|
||||
RemoveDevice("romfs:");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -292,15 +403,15 @@ static u32 calcHash(u32 parent, u16* name, u32 namelen, u32 total)
|
||||
return hash % total;
|
||||
}
|
||||
|
||||
static romfs_dir* searchForDir(romfs_dir* parent, u16* name, u32 namelen)
|
||||
static romfs_dir* searchForDir(romfs_mount *mount, romfs_dir* parent, u16* name, u32 namelen)
|
||||
{
|
||||
u32 parentOff = (u32)parent - (u32)dirTable;
|
||||
u32 hash = calcHash(parentOff, name, namelen, romFS_header.dirHashTableSize/4);
|
||||
u32 parentOff = (u32)parent - (u32)mount->dirTable;
|
||||
u32 hash = calcHash(parentOff, name, namelen, mount->header.dirHashTableSize/4);
|
||||
romfs_dir* curDir = NULL;
|
||||
u32 curOff;
|
||||
for (curOff = dirHashTable[hash]; curOff != romFS_none; curOff = curDir->nextHash)
|
||||
for (curOff = mount->dirHashTable[hash]; curOff != romFS_none; curOff = curDir->nextHash)
|
||||
{
|
||||
curDir = romFS_dir(curOff);
|
||||
curDir = romFS_dir(mount, curOff);
|
||||
if (curDir->parent != parentOff) continue;
|
||||
if (curDir->nameLen != namelen*2) continue;
|
||||
if (memcmp(curDir->name, name, namelen*2) != 0) continue;
|
||||
@ -309,15 +420,15 @@ static romfs_dir* searchForDir(romfs_dir* parent, u16* name, u32 namelen)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static romfs_file* searchForFile(romfs_dir* parent, u16* name, u32 namelen)
|
||||
static romfs_file* searchForFile(romfs_mount *mount, romfs_dir* parent, u16* name, u32 namelen)
|
||||
{
|
||||
u32 parentOff = (u32)parent - (u32)dirTable;
|
||||
u32 hash = calcHash(parentOff, name, namelen, romFS_header.fileHashTableSize/4);
|
||||
u32 parentOff = (u32)parent - (u32)mount->dirTable;
|
||||
u32 hash = calcHash(parentOff, name, namelen, mount->header.fileHashTableSize/4);
|
||||
romfs_file* curFile = NULL;
|
||||
u32 curOff;
|
||||
for (curOff = fileHashTable[hash]; curOff != romFS_none; curOff = curFile->nextHash)
|
||||
for (curOff = mount->fileHashTable[hash]; curOff != romFS_none; curOff = curFile->nextHash)
|
||||
{
|
||||
curFile = romFS_file(curOff);
|
||||
curFile = romFS_file(mount, curOff);
|
||||
if (curFile->parent != parentOff) continue;
|
||||
if (curFile->nameLen != namelen*2) continue;
|
||||
if (memcmp(curFile->name, name, namelen*2) != 0) continue;
|
||||
@ -326,7 +437,7 @@ static romfs_file* searchForFile(romfs_dir* parent, u16* name, u32 namelen)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int navigateToDir(romfs_dir** ppDir, const char** pPath, bool isDir)
|
||||
static int navigateToDir(romfs_mount *mount, romfs_dir** ppDir, const char** pPath, bool isDir)
|
||||
{
|
||||
ssize_t units;
|
||||
|
||||
@ -335,10 +446,10 @@ static int navigateToDir(romfs_dir** ppDir, const char** pPath, bool isDir)
|
||||
if (!**pPath)
|
||||
return EILSEQ;
|
||||
|
||||
*ppDir = romFS_cwd;
|
||||
*ppDir = mount->cwd;
|
||||
if (**pPath == '/')
|
||||
{
|
||||
*ppDir = romFS_root;
|
||||
*ppDir = romFS_root(mount);
|
||||
(*pPath)++;
|
||||
}
|
||||
|
||||
@ -370,7 +481,7 @@ static int navigateToDir(romfs_dir** ppDir, const char** pPath, bool isDir)
|
||||
if (!component[1]) continue;
|
||||
if (component[1]=='.' && !component[2])
|
||||
{
|
||||
*ppDir = romFS_dir((*ppDir)->parent);
|
||||
*ppDir = romFS_dir(mount, (*ppDir)->parent);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -381,7 +492,7 @@ static int navigateToDir(romfs_dir** ppDir, const char** pPath, bool isDir)
|
||||
if (units >= PATH_MAX)
|
||||
return ENAMETOOLONG;
|
||||
|
||||
*ppDir = searchForDir(*ppDir, __utf16path, units);
|
||||
*ppDir = searchForDir(mount, *ppDir, __utf16path, units);
|
||||
if (!*ppDir)
|
||||
return EEXIST;
|
||||
}
|
||||
@ -392,9 +503,9 @@ static int navigateToDir(romfs_dir** ppDir, const char** pPath, bool isDir)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ino_t dir_inode(romfs_dir *dir)
|
||||
static ino_t dir_inode(romfs_mount *mount, romfs_dir *dir)
|
||||
{
|
||||
return (uint32_t*)dir - (uint32_t*)dirTable;
|
||||
return (uint32_t*)dir - (uint32_t*)mount->dirTable;
|
||||
}
|
||||
|
||||
static off_t dir_size(romfs_dir *dir)
|
||||
@ -402,14 +513,14 @@ static off_t dir_size(romfs_dir *dir)
|
||||
return sizeof(romfs_dir) + (dir->nameLen+3)/4;
|
||||
}
|
||||
|
||||
static nlink_t dir_nlink(romfs_dir *dir)
|
||||
static nlink_t dir_nlink(romfs_mount *mount, romfs_dir *dir)
|
||||
{
|
||||
nlink_t count = 2; // one for self, one for parent
|
||||
u32 offset = dir->childDir;
|
||||
|
||||
while(offset != romFS_none)
|
||||
{
|
||||
romfs_dir *tmp = romFS_dir(offset);
|
||||
romfs_dir *tmp = romFS_dir(mount, offset);
|
||||
++count;
|
||||
offset = tmp->sibling;
|
||||
}
|
||||
@ -417,7 +528,7 @@ static nlink_t dir_nlink(romfs_dir *dir)
|
||||
offset = dir->childFile;
|
||||
while(offset != romFS_none)
|
||||
{
|
||||
romfs_file *tmp = romFS_file(offset);
|
||||
romfs_file *tmp = romFS_file(mount, offset);
|
||||
++count;
|
||||
offset = tmp->sibling;
|
||||
}
|
||||
@ -425,9 +536,9 @@ static nlink_t dir_nlink(romfs_dir *dir)
|
||||
return count;
|
||||
}
|
||||
|
||||
static ino_t file_inode(romfs_file *file)
|
||||
static ino_t file_inode(romfs_mount *mount, romfs_file *file)
|
||||
{
|
||||
return ((uint32_t*)file - (uint32_t*)fileTable) + romFS_header.dirTableSize/4;
|
||||
return ((uint32_t*)file - (uint32_t*)mount->fileTable) + mount->header.dirTableSize/4;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -436,6 +547,8 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
|
||||
{
|
||||
romfs_fileobj* fileobj = (romfs_fileobj*)fileStruct;
|
||||
|
||||
fileobj->mount = romfs_mount_list;
|
||||
|
||||
if ((flags & O_ACCMODE) != O_RDONLY)
|
||||
{
|
||||
r->_errno = EROFS;
|
||||
@ -443,7 +556,7 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
|
||||
}
|
||||
|
||||
romfs_dir* curDir = NULL;
|
||||
r->_errno = navigateToDir(&curDir, &path, false);
|
||||
r->_errno = navigateToDir(fileobj->mount, &curDir, &path, false);
|
||||
if (r->_errno != 0)
|
||||
return -1;
|
||||
|
||||
@ -459,7 +572,7 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
|
||||
return -1;
|
||||
}
|
||||
|
||||
romfs_file* file = searchForFile(curDir, __utf16path, units);
|
||||
romfs_file* file = searchForFile(fileobj->mount, curDir, __utf16path, units);
|
||||
if (!file)
|
||||
{
|
||||
if(flags & O_CREAT)
|
||||
@ -475,7 +588,7 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
|
||||
}
|
||||
|
||||
fileobj->file = file;
|
||||
fileobj->offset = (u64)romFS_header.fileDataOff + file->dataOff;
|
||||
fileobj->offset = (u64)fileobj->mount->header.fileDataOff + file->dataOff;
|
||||
fileobj->pos = 0;
|
||||
|
||||
return 0;
|
||||
@ -500,7 +613,7 @@ ssize_t romfs_read(struct _reent *r, int fd, char *ptr, size_t len)
|
||||
endPos = file->file->dataSize;
|
||||
len = endPos - file->pos;
|
||||
|
||||
ssize_t adv = _romfs_read(file->offset + file->pos, ptr, len);
|
||||
ssize_t adv = _romfs_read(file->mount, file->offset + file->pos, ptr, len);
|
||||
if(adv >= 0)
|
||||
{
|
||||
file->pos += adv;
|
||||
@ -558,21 +671,22 @@ int romfs_fstat(struct _reent *r, int fd, struct stat *st)
|
||||
{
|
||||
romfs_fileobj* file = (romfs_fileobj*)fd;
|
||||
memset(st, 0, sizeof(struct stat));
|
||||
st->st_ino = file_inode(file->file);
|
||||
st->st_ino = file_inode(file->mount, file->file);
|
||||
st->st_mode = romFS_file_mode;
|
||||
st->st_nlink = 1;
|
||||
st->st_size = (off_t)file->file->dataSize;
|
||||
st->st_blksize = 512;
|
||||
st->st_blocks = (st->st_blksize + 511) / 512;
|
||||
st->st_atime = st->st_mtime = st->st_ctime = romFS_mtime;
|
||||
st->st_atime = st->st_mtime = st->st_ctime = file->mount->mtime;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int romfs_stat(struct _reent *r, const char *path, struct stat *st)
|
||||
{
|
||||
romfs_mount* mount = romfs_mount_list;
|
||||
romfs_dir* curDir = NULL;
|
||||
r->_errno = navigateToDir(&curDir, &path, false);
|
||||
r->_errno = navigateToDir(mount, &curDir, &path, false);
|
||||
if(r->_errno != 0)
|
||||
return -1;
|
||||
|
||||
@ -588,32 +702,32 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
|
||||
return -1;
|
||||
}
|
||||
|
||||
romfs_dir* dir = searchForDir(curDir, __utf16path, units);
|
||||
romfs_dir* dir = searchForDir(mount, curDir, __utf16path, units);
|
||||
if(dir)
|
||||
{
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_ino = dir_inode(dir);
|
||||
st->st_ino = dir_inode(mount, dir);
|
||||
st->st_mode = romFS_dir_mode;
|
||||
st->st_nlink = dir_nlink(dir);
|
||||
st->st_nlink = dir_nlink(mount, dir);
|
||||
st->st_size = dir_size(dir);
|
||||
st->st_blksize = 512;
|
||||
st->st_blocks = (st->st_blksize + 511) / 512;
|
||||
st->st_atime = st->st_mtime = st->st_ctime = romFS_mtime;
|
||||
st->st_atime = st->st_mtime = st->st_ctime = mount->mtime;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
romfs_file* file = searchForFile(curDir, __utf16path, units);
|
||||
romfs_file* file = searchForFile(mount, curDir, __utf16path, units);
|
||||
if(file)
|
||||
{
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_ino = file_inode(file);
|
||||
st->st_ino = file_inode(mount, file);
|
||||
st->st_mode = romFS_file_mode;
|
||||
st->st_nlink = 1;
|
||||
st->st_size = file->dataSize;
|
||||
st->st_blksize = 512;
|
||||
st->st_blocks = (st->st_blksize + 511) / 512;
|
||||
st->st_atime = st->st_mtime = st->st_ctime = romFS_mtime;
|
||||
st->st_atime = st->st_mtime = st->st_ctime = mount->mtime;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -624,12 +738,13 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
|
||||
|
||||
int romfs_chdir(struct _reent *r, const char *path)
|
||||
{
|
||||
romfs_mount* mount = romfs_mount_list;
|
||||
romfs_dir* curDir = NULL;
|
||||
r->_errno = navigateToDir(&curDir, &path, true);
|
||||
r->_errno = navigateToDir(mount, &curDir, &path, true);
|
||||
if (r->_errno != 0)
|
||||
return -1;
|
||||
|
||||
romFS_cwd = curDir;
|
||||
mount->cwd = curDir;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -637,8 +752,9 @@ DIR_ITER* romfs_diropen(struct _reent *r, DIR_ITER *dirState, const char *path)
|
||||
{
|
||||
romfs_diriter* iter = (romfs_diriter*)(dirState->dirStruct);
|
||||
romfs_dir* curDir = NULL;
|
||||
iter->mount = romfs_mount_list;
|
||||
|
||||
r->_errno = navigateToDir(&curDir, &path, true);
|
||||
r->_errno = navigateToDir(iter->mount, &curDir, &path, true);
|
||||
if(r->_errno != 0)
|
||||
return NULL;
|
||||
|
||||
@ -670,7 +786,7 @@ int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct s
|
||||
{
|
||||
/* '.' entry */
|
||||
memset(filestat, 0, sizeof(*filestat));
|
||||
filestat->st_ino = dir_inode(iter->dir);
|
||||
filestat->st_ino = dir_inode(iter->mount, iter->dir);
|
||||
filestat->st_mode = romFS_dir_mode;
|
||||
|
||||
strcpy(filename, ".");
|
||||
@ -680,10 +796,10 @@ int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct s
|
||||
else if(iter->state == 1)
|
||||
{
|
||||
/* '..' entry */
|
||||
romfs_dir* dir = romFS_dir(iter->dir->parent);
|
||||
romfs_dir* dir = romFS_dir(iter->mount, iter->dir->parent);
|
||||
|
||||
memset(filestat, 0, sizeof(*filestat));
|
||||
filestat->st_ino = dir_inode(dir);
|
||||
filestat->st_ino = dir_inode(iter->mount, dir);
|
||||
filestat->st_mode = romFS_dir_mode;
|
||||
|
||||
strcpy(filename, "..");
|
||||
@ -693,11 +809,11 @@ int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct s
|
||||
|
||||
if(iter->childDir != romFS_none)
|
||||
{
|
||||
romfs_dir* dir = romFS_dir(iter->childDir);
|
||||
romfs_dir* dir = romFS_dir(iter->mount, iter->childDir);
|
||||
iter->childDir = dir->sibling;
|
||||
|
||||
memset(filestat, 0, sizeof(*filestat));
|
||||
filestat->st_ino = dir_inode(dir);
|
||||
filestat->st_ino = dir_inode(iter->mount, dir);
|
||||
filestat->st_mode = romFS_dir_mode;
|
||||
|
||||
/* convert name from UTF-16 to UTF-8 */
|
||||
@ -724,11 +840,11 @@ int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct s
|
||||
}
|
||||
else if(iter->childFile != romFS_none)
|
||||
{
|
||||
romfs_file* file = romFS_file(iter->childFile);
|
||||
romfs_file* file = romFS_file(iter->mount, iter->childFile);
|
||||
iter->childFile = file->sibling;
|
||||
|
||||
memset(filestat, 0, sizeof(*filestat));
|
||||
filestat->st_ino = file_inode(file);
|
||||
filestat->st_ino = file_inode(iter->mount, file);
|
||||
filestat->st_mode = romFS_file_mode;
|
||||
|
||||
/* convert name from UTF-16 to UTF-8 */
|
||||
|
@ -20,6 +20,18 @@ Result amInit(void)
|
||||
ret = srvGetServiceHandle(&amHandle, "am:net");
|
||||
if (R_FAILED(ret)) ret = srvGetServiceHandle(&amHandle, "am:u");
|
||||
if (R_FAILED(ret)) ret = srvGetServiceHandle(&amHandle, "am:sys");
|
||||
if (R_FAILED(ret)) AtomicDecrement(&amRefCount);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result amAppInit(void)
|
||||
{
|
||||
Result ret;
|
||||
|
||||
if (AtomicPostIncrement(&amRefCount)) return 0;
|
||||
|
||||
ret = srvGetServiceHandle(&amHandle, "am:sys");
|
||||
if (R_FAILED(ret)) ret = srvGetServiceHandle(&amHandle, "am:app");
|
||||
if (R_FAILED(ret)) AtomicDecrement(&amRefCount);
|
||||
|
||||
@ -548,7 +560,7 @@ Result AM_QueryAvailableExternalTitleDatabase(bool* available)
|
||||
if(R_FAILED(ret = (Result)cmdbuf[1])) return ret;
|
||||
|
||||
// Only accept this if the command was a success
|
||||
if(available) *available = cmdbuf[2];
|
||||
if(available) *available = cmdbuf[2] & 0xFF;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -457,7 +457,7 @@ Result CAMU_SetLensCorrection(u32 select, CAMU_LensCorrection lensCorrection) {
|
||||
Result CAMU_SetOutputFormat(u32 select, CAMU_OutputFormat format, CAMU_Context context) {
|
||||
Result ret = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = IPC_MakeHeader(0x25,2,0); // 0x2500C0
|
||||
cmdbuf[0] = IPC_MakeHeader(0x25,3,0); // 0x2500C0
|
||||
cmdbuf[1] = select;
|
||||
cmdbuf[2] = format;
|
||||
cmdbuf[3] = context;
|
||||
|
@ -1137,8 +1137,8 @@ Result FSUSER_ExportIntegrityVerificationSeed(FS_IntegrityVerificationSeed* seed
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x84A,0,2); // 0x84A0002
|
||||
cmdbuf[2] = IPC_Desc_Buffer(sizeof(FS_IntegrityVerificationSeed), IPC_BUFFER_W);
|
||||
cmdbuf[3] = (u32) seed;
|
||||
cmdbuf[1] = IPC_Desc_Buffer(sizeof(FS_IntegrityVerificationSeed), IPC_BUFFER_W);
|
||||
cmdbuf[2] = (u32) seed;
|
||||
|
||||
Result ret = 0;
|
||||
if(R_FAILED(ret = svcSendSyncRequest(fsSession()))) return ret;
|
||||
@ -1151,8 +1151,8 @@ Result FSUSER_ImportIntegrityVerificationSeed(FS_IntegrityVerificationSeed* seed
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x84B,0,2); // 0x84B0002
|
||||
cmdbuf[2] = IPC_Desc_Buffer(sizeof(FS_IntegrityVerificationSeed), IPC_BUFFER_R);
|
||||
cmdbuf[3] = (u32) seed;
|
||||
cmdbuf[1] = IPC_Desc_Buffer(sizeof(FS_IntegrityVerificationSeed), IPC_BUFFER_R);
|
||||
cmdbuf[2] = (u32) seed;
|
||||
|
||||
Result ret = 0;
|
||||
if(R_FAILED(ret = svcSendSyncRequest(fsSession()))) return ret;
|
||||
|
@ -14,19 +14,22 @@
|
||||
Handle gspGpuHandle;
|
||||
static int gspRefCount;
|
||||
|
||||
Handle gspEvents[GSPGPU_EVENT_MAX];
|
||||
vu32 gspEventCounts[GSPGPU_EVENT_MAX];
|
||||
ThreadFunc gspEventCb[GSPGPU_EVENT_MAX];
|
||||
void* gspEventCbData[GSPGPU_EVENT_MAX];
|
||||
bool gspEventCbOneShot[GSPGPU_EVENT_MAX];
|
||||
volatile bool gspRunEvents;
|
||||
Thread gspEventThread;
|
||||
static s32 gspLastEvent = -1;
|
||||
static LightEvent gspEvents[GSPGPU_EVENT_MAX];
|
||||
static vu32 gspEventCounts[GSPGPU_EVENT_MAX];
|
||||
static ThreadFunc gspEventCb[GSPGPU_EVENT_MAX];
|
||||
static void* gspEventCbData[GSPGPU_EVENT_MAX];
|
||||
static bool gspEventCbOneShot[GSPGPU_EVENT_MAX];
|
||||
static volatile bool gspRunEvents;
|
||||
static Thread gspEventThread;
|
||||
|
||||
static Handle gspEvent;
|
||||
static vu8* gspEventData;
|
||||
|
||||
static void gspEventThreadMain(void *arg);
|
||||
|
||||
Handle __sync_get_arbiter(void);
|
||||
|
||||
Result gspInit(void)
|
||||
{
|
||||
Result res=0;
|
||||
@ -53,20 +56,10 @@ void gspSetEventCallback(GSPGPU_Event id, ThreadFunc cb, void* data, bool oneSho
|
||||
|
||||
Result gspInitEventHandler(Handle _gspEvent, vu8* _gspSharedMem, u8 gspThreadId)
|
||||
{
|
||||
// Create events
|
||||
// Initialize events
|
||||
int i;
|
||||
for (i = 0; i < GSPGPU_EVENT_MAX; i ++)
|
||||
{
|
||||
Result rc = svcCreateEvent(&gspEvents[i], 0);
|
||||
if (rc != 0)
|
||||
{
|
||||
// Destroy already created events due to failure
|
||||
int j;
|
||||
for (j = 0; j < i; j ++)
|
||||
svcCloseHandle(gspEvents[j]);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
LightEvent_Init(&gspEvents[i], RESET_STICKY);
|
||||
|
||||
// Start event thread
|
||||
gspEvent = _gspEvent;
|
||||
@ -82,11 +75,6 @@ void gspExitEventHandler(void)
|
||||
gspRunEvents = false;
|
||||
svcSignalEvent(gspEvent);
|
||||
threadJoin(gspEventThread, U64_MAX);
|
||||
|
||||
// Free events
|
||||
int i;
|
||||
for (i = 0; i < GSPGPU_EVENT_MAX; i ++)
|
||||
svcCloseHandle(gspEvents[i]);
|
||||
}
|
||||
|
||||
void gspWaitForEvent(GSPGPU_Event id, bool nextEvent)
|
||||
@ -94,19 +82,30 @@ void gspWaitForEvent(GSPGPU_Event id, bool nextEvent)
|
||||
if(id>= GSPGPU_EVENT_MAX)return;
|
||||
|
||||
if (nextEvent)
|
||||
svcClearEvent(gspEvents[id]);
|
||||
svcWaitSynchronization(gspEvents[id], U64_MAX);
|
||||
LightEvent_Clear(&gspEvents[id]);
|
||||
LightEvent_Wait(&gspEvents[id]);
|
||||
if (!nextEvent)
|
||||
svcClearEvent(gspEvents[id]);
|
||||
LightEvent_Clear(&gspEvents[id]);
|
||||
}
|
||||
|
||||
GSPGPU_Event gspWaitForAnyEvent(void)
|
||||
{
|
||||
s32 which = 0;
|
||||
Result rc = svcWaitSynchronizationN(&which, gspEvents, GSPGPU_EVENT_MAX, false, U64_MAX);
|
||||
if (R_FAILED(rc)) return -1;
|
||||
svcClearEvent(gspEvents[which]);
|
||||
return which;
|
||||
s32 x;
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
x = __ldrex(&gspLastEvent);
|
||||
if (x < 0)
|
||||
{
|
||||
__clrex();
|
||||
break;
|
||||
}
|
||||
} while (__strex(&gspLastEvent, -1));
|
||||
if (x < 0)
|
||||
svcArbitrateAddress(__sync_get_arbiter(), (u32)&gspLastEvent, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
|
||||
} while (x < 0);
|
||||
return (GSPGPU_Event)x;
|
||||
}
|
||||
|
||||
static int popInterrupt()
|
||||
@ -168,7 +167,11 @@ void gspEventThreadMain(void *arg)
|
||||
gspEventCb[curEvt] = NULL;
|
||||
func(gspEventCbData[curEvt]);
|
||||
}
|
||||
svcSignalEvent(gspEvents[curEvt]);
|
||||
LightEvent_Signal(&gspEvents[curEvt]);
|
||||
do
|
||||
__ldrex(&gspLastEvent);
|
||||
while (__strex(&gspLastEvent, curEvt));
|
||||
svcArbitrateAddress(__sync_get_arbiter(), (u32)&gspLastEvent, ARBITRATION_SIGNAL, 1, 0);
|
||||
gspEventCounts[curEvt]++;
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ static int hidRefCount;
|
||||
|
||||
Result hidInit(void)
|
||||
{
|
||||
u8 val=0;
|
||||
bool val=false;
|
||||
Result ret=0;
|
||||
|
||||
if (AtomicPostIncrement(&hidRefCount)) return 0;
|
||||
@ -84,7 +84,7 @@ void hidExit(void)
|
||||
if (AtomicDecrement(&hidRefCount)) return;
|
||||
|
||||
// Unmap HID sharedmem and close handles.
|
||||
u8 val=0;
|
||||
bool val=false;
|
||||
int i; for(i=0; i<5; i++)svcCloseHandle(hidEvents[i]);
|
||||
svcUnmapMemoryBlock(hidMemHandle, (u32)hidSharedMem);
|
||||
svcCloseHandle(hidMemHandle);
|
||||
|
@ -20,7 +20,7 @@ static Handle __httpc_sharedmem_handle;
|
||||
static Result HTTPC_Initialize(Handle handle, u32 sharedmem_size, Handle sharedmem_handle);
|
||||
static Result HTTPC_Finalize(Handle handle);
|
||||
|
||||
static Result HTTPC_CreateContext(Handle handle, HTTPC_RequestMethod method, char* url, Handle* contextHandle);
|
||||
static Result HTTPC_CreateContext(Handle handle, HTTPC_RequestMethod method, const char* url, Handle* contextHandle);
|
||||
static Result HTTPC_CloseContext(Handle handle, Handle contextHandle);
|
||||
|
||||
static Result HTTPC_InitializeConnectionSession(Handle handle, Handle contextHandle);
|
||||
@ -87,7 +87,7 @@ void httpcExit(void)
|
||||
}
|
||||
}
|
||||
|
||||
Result httpcOpenContext(httpcContext *context, HTTPC_RequestMethod method, char* url, u32 use_defaultproxy)
|
||||
Result httpcOpenContext(httpcContext *context, HTTPC_RequestMethod method, const char* url, u32 use_defaultproxy)
|
||||
{
|
||||
Result ret=0;
|
||||
|
||||
@ -129,6 +129,19 @@ Result httpcCloseContext(httpcContext *context)
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result httpcCancelConnection(httpcContext *context)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0]=IPC_MakeHeader(0x4,1,0); // 0x40040
|
||||
cmdbuf[1]=context->httphandle;
|
||||
|
||||
Result ret=0;
|
||||
if(R_FAILED(ret=svcSendSyncRequest(__httpc_servhandle)))return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcDownloadData(httpcContext *context, u8* buffer, u32 size, u32 *downloadedsize)
|
||||
{
|
||||
Result ret=0;
|
||||
@ -187,7 +200,7 @@ static Result HTTPC_Finalize(Handle handle)
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
static Result HTTPC_CreateContext(Handle handle, HTTPC_RequestMethod method, char* url, Handle* contextHandle)
|
||||
static Result HTTPC_CreateContext(Handle handle, HTTPC_RequestMethod method, const char* url, Handle* contextHandle)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
u32 l=strlen(url)+1;
|
||||
@ -246,7 +259,7 @@ static Result HTTPC_CloseContext(Handle handle, Handle contextHandle)
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcAddRequestHeaderField(httpcContext *context, char* name, char* value)
|
||||
Result httpcAddRequestHeaderField(httpcContext *context, const char* name, const char* value)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -268,7 +281,7 @@ Result httpcAddRequestHeaderField(httpcContext *context, char* name, char* value
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcAddPostDataAscii(httpcContext *context, char* name, char* value)
|
||||
Result httpcAddPostDataAscii(httpcContext *context, const char* name, const char* value)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -290,7 +303,7 @@ Result httpcAddPostDataAscii(httpcContext *context, char* name, char* value)
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcAddPostDataRaw(httpcContext *context, u32* data, u32 len)
|
||||
Result httpcAddPostDataRaw(httpcContext *context, const u32* data, u32 len)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -337,6 +350,24 @@ Result httpcReceiveData(httpcContext *context, u8* buffer, u32 size)
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcReceiveDataTimeout(httpcContext *context, u8* buffer, u32 size, u64 timeout)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0]=IPC_MakeHeader(0xC,4,2); // 0xC0102
|
||||
cmdbuf[1]=context->httphandle;
|
||||
cmdbuf[2]=size;
|
||||
cmdbuf[3]=timeout & 0xffffffff;
|
||||
cmdbuf[4]=(timeout >> 32) & 0xffffffff;
|
||||
cmdbuf[5]=IPC_Desc_Buffer(size,IPC_BUFFER_W);
|
||||
cmdbuf[6]=(u32)buffer;
|
||||
|
||||
Result ret=0;
|
||||
if(R_FAILED(ret=svcSendSyncRequest(context->servhandle)))return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcGetRequestState(httpcContext *context, HTTPC_RequestStatus* out)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
@ -367,7 +398,7 @@ Result httpcGetDownloadSizeState(httpcContext *context, u32* downloadedsize, u32
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
Result httpcGetResponseHeader(httpcContext *context, char* name, char* value, u32 valuebuf_maxsize)
|
||||
Result httpcGetResponseHeader(httpcContext *context, const char* name, char* value, u32 valuebuf_maxsize)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -388,7 +419,7 @@ Result httpcGetResponseHeader(httpcContext *context, char* name, char* value, u3
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcGetResponseStatusCode(httpcContext *context, u32* out, u64 delay)
|
||||
Result httpcGetResponseStatusCode(httpcContext *context, u32* out)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -403,7 +434,25 @@ Result httpcGetResponseStatusCode(httpcContext *context, u32* out, u64 delay)
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcAddTrustedRootCA(httpcContext *context, u8 *cert, u32 certsize)
|
||||
|
||||
Result httpcGetResponseStatusCodeTimeout(httpcContext *context, u32* out, u64 timeout)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0]=IPC_MakeHeader(0x23,3,0); // 0x2300C0
|
||||
cmdbuf[1]=context->httphandle;
|
||||
cmdbuf[2]=timeout & 0xffffffff;
|
||||
cmdbuf[3]=(timeout >> 32) & 0xffffffff;
|
||||
|
||||
Result ret=0;
|
||||
if(R_FAILED(ret=svcSendSyncRequest(context->servhandle)))return ret;
|
||||
|
||||
*out = cmdbuf[2];
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcAddTrustedRootCA(httpcContext *context, const u8 *cert, u32 certsize)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -447,7 +496,7 @@ Result httpcSelectRootCertChain(httpcContext *context, u32 RootCertChain_context
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcSetClientCert(httpcContext *context, u8 *cert, u32 certsize, u8 *privk, u32 privk_size)
|
||||
Result httpcSetClientCert(httpcContext *context, const u8 *cert, u32 certsize, const u8 *privk, u32 privk_size)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -550,7 +599,7 @@ Result httpcDestroyRootCertChain(u32 RootCertChain_contexthandle)
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcRootCertChainAddCert(u32 RootCertChain_contexthandle, u8 *cert, u32 certsize, u32 *cert_contexthandle)
|
||||
Result httpcRootCertChainAddCert(u32 RootCertChain_contexthandle, const u8 *cert, u32 certsize, u32 *cert_contexthandle)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -600,7 +649,7 @@ Result httpcRootCertChainRemoveCert(u32 RootCertChain_contexthandle, u32 cert_co
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcOpenClientCertContext(u8 *cert, u32 certsize, u8 *privk, u32 privk_size, u32 *ClientCert_contexthandle)
|
||||
Result httpcOpenClientCertContext(const u8 *cert, u32 certsize, const u8 *privk, u32 privk_size, u32 *ClientCert_contexthandle)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -649,3 +698,17 @@ Result httpcCloseClientCertContext(u32 ClientCert_contexthandle)
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result httpcSetKeepAlive(httpcContext *context, HTTPC_KeepAlive option)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0]=IPC_MakeHeader(0x37,2,0); // 0x370080
|
||||
cmdbuf[1]=context->httphandle;
|
||||
cmdbuf[2]=option;
|
||||
|
||||
Result ret=0;
|
||||
if(R_FAILED(ret=svcSendSyncRequest(context->servhandle)))return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
@ -60,12 +60,12 @@ Handle nfcGetSessionHandle(void)
|
||||
Result nfcStartScanning(u16 inval)
|
||||
{
|
||||
Result ret, ret2;
|
||||
u8 new3ds_flag = 0;
|
||||
bool new3ds_flag = false;
|
||||
u8 status;
|
||||
|
||||
APT_CheckNew3DS(&new3ds_flag);
|
||||
|
||||
if(new3ds_flag==0)
|
||||
if(!new3ds_flag)
|
||||
{
|
||||
ret = NFC_StartCommunication();
|
||||
if(R_FAILED(ret))return ret;
|
||||
@ -102,13 +102,13 @@ Result nfcStartScanning(u16 inval)
|
||||
|
||||
void nfcStopScanning(void)
|
||||
{
|
||||
u8 new3ds_flag = 0;
|
||||
bool new3ds_flag = false;
|
||||
|
||||
APT_CheckNew3DS(&new3ds_flag);
|
||||
|
||||
NFC_StopTagScanning();
|
||||
|
||||
if(new3ds_flag==0)
|
||||
if(!new3ds_flag)
|
||||
{
|
||||
NFC_StopCommunication();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/svc.h>
|
||||
@ -34,10 +35,7 @@ Result PS_EncryptDecryptAes(u32 size, u8* in, u8* out, PS_AESAlgorithm aes_algo,
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x4,7,4); // 0x401C4
|
||||
cmdbuf[1] = size;
|
||||
cmdbuf[2] = _iv[0];
|
||||
cmdbuf[3] = _iv[1];
|
||||
cmdbuf[4] = _iv[2];
|
||||
cmdbuf[5] = _iv[3];
|
||||
memcpy(&cmdbuf[2], _iv, 16);
|
||||
cmdbuf[6] = aes_algo;
|
||||
cmdbuf[7] = key_type;
|
||||
cmdbuf[8] = IPC_Desc_PXIBuffer(size,0,false);
|
||||
@ -47,10 +45,7 @@ Result PS_EncryptDecryptAes(u32 size, u8* in, u8* out, PS_AESAlgorithm aes_algo,
|
||||
|
||||
if(R_FAILED(ret = svcSendSyncRequest(psHandle)))return ret;
|
||||
|
||||
_iv[0] = cmdbuf[2] & 0xFF;
|
||||
_iv[1] = cmdbuf[3] & 0xFF;
|
||||
_iv[2] = cmdbuf[4] & 0xFF;
|
||||
_iv[3] = cmdbuf[5] & 0xFF;
|
||||
memcpy(_iv, &cmdbuf[2], 16);
|
||||
|
||||
return (Result)cmdbuf[1];
|
||||
}
|
||||
@ -68,15 +63,13 @@ Result PS_EncryptSignDecryptVerifyAesCcm(u8* in, u32 in_size, u8* out, u32 out_s
|
||||
cmdbuf[3] = mac_data_len;
|
||||
cmdbuf[4] = data_len;
|
||||
cmdbuf[5] = mac_len;
|
||||
cmdbuf[6] = _nonce[0];
|
||||
cmdbuf[7] = _nonce[1];
|
||||
cmdbuf[8] = _nonce[2];
|
||||
memcpy(&cmdbuf[6], _nonce, 12);
|
||||
cmdbuf[9] = aes_algo;
|
||||
cmdbuf[10] = key_type;
|
||||
cmdbuf[8] = IPC_Desc_PXIBuffer(in_size,0,false);
|
||||
cmdbuf[9] = (u32)in;
|
||||
cmdbuf[10] = IPC_Desc_PXIBuffer(out_size,1,false);
|
||||
cmdbuf[11] = (u32)out;
|
||||
cmdbuf[11] = IPC_Desc_PXIBuffer(in_size,0,false);
|
||||
cmdbuf[12] = (u32)in;
|
||||
cmdbuf[13] = IPC_Desc_PXIBuffer(out_size,1,false);
|
||||
cmdbuf[14] = (u32)out;
|
||||
|
||||
if(R_FAILED(ret = svcSendSyncRequest(psHandle)))return ret;
|
||||
|
||||
@ -110,3 +103,18 @@ Result PS_GetDeviceId(u32* device_id)
|
||||
|
||||
return (Result)cmdbuf[1];
|
||||
}
|
||||
|
||||
Result PS_GenerateRandomBytes(void* out, size_t len)
|
||||
{
|
||||
Result ret = 0;
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0xD,1,2); // 0xD0042
|
||||
cmdbuf[1] = len;
|
||||
cmdbuf[2] = IPC_Desc_Buffer(len, IPC_BUFFER_W);
|
||||
cmdbuf[3] = (u32)out;
|
||||
|
||||
if(R_FAILED(ret = svcSendSyncRequest(psHandle)))return ret;
|
||||
|
||||
return (Result)cmdbuf[1];
|
||||
}
|
||||
|
101
libctru/source/services/pxidev.c
Normal file
101
libctru/source/services/pxidev.c
Normal file
@ -0,0 +1,101 @@
|
||||
#include <string.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/srv.h>
|
||||
#include <3ds/synchronization.h>
|
||||
#include <3ds/services/pxidev.h>
|
||||
#include <3ds/ipc.h>
|
||||
|
||||
static Handle pxiDevHandle;
|
||||
static int pxiDevRefCount;
|
||||
|
||||
Result pxiDevInit(void)
|
||||
{
|
||||
Result ret;
|
||||
|
||||
if (AtomicPostIncrement(&pxiDevRefCount)) return 0;
|
||||
|
||||
ret = srvGetServiceHandle(&pxiDevHandle, "pxi:dev");
|
||||
if (R_FAILED(ret)) AtomicDecrement(&pxiDevRefCount);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pxiDevExit(void)
|
||||
{
|
||||
if (AtomicDecrement(&pxiDevRefCount)) return;
|
||||
svcCloseHandle(pxiDevHandle);
|
||||
}
|
||||
|
||||
Result PXIDEV_SPIMultiWriteRead(PXIDEV_SPIBuffer* header, PXIDEV_SPIBuffer* writeBuffer1, PXIDEV_SPIBuffer* readBuffer1, PXIDEV_SPIBuffer* writeBuffer2, PXIDEV_SPIBuffer* readBuffer2, PXIDEV_SPIBuffer* footer)
|
||||
{
|
||||
Result ret=0;
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0xD,26,8); // 0x000D0688
|
||||
memcpy(&cmdbuf[1], header->ptr, header->size);
|
||||
cmdbuf[3] = header->size;
|
||||
cmdbuf[4] = header->transferOption;
|
||||
cmdbuf[5] = (u32) (header->waitOperation & 0xFFFFFFFF);
|
||||
cmdbuf[6] = (u32) ((header->waitOperation >> 32) & 0xFFFFFFFF);
|
||||
cmdbuf[7] = writeBuffer1->size;
|
||||
cmdbuf[8] = writeBuffer1->transferOption;
|
||||
cmdbuf[9] = (u32) (writeBuffer1->waitOperation & 0xFFFFFFFF);
|
||||
cmdbuf[10] = (u32) ((writeBuffer1->waitOperation >> 32) & 0xFFFFFFFF);
|
||||
cmdbuf[11] = readBuffer1->size;
|
||||
cmdbuf[12] = readBuffer1->transferOption;
|
||||
cmdbuf[13] = (u32) (readBuffer1->waitOperation & 0xFFFFFFFF);
|
||||
cmdbuf[14] = (u32) ((readBuffer1->waitOperation >> 32) & 0xFFFFFFFF);
|
||||
cmdbuf[15] = writeBuffer2->size;
|
||||
cmdbuf[16] = writeBuffer2->transferOption;
|
||||
cmdbuf[17] = (u32) (writeBuffer2->waitOperation & 0xFFFFFFFF);
|
||||
cmdbuf[18] = (u32) ((writeBuffer2->waitOperation >> 32) & 0xFFFFFFFF);
|
||||
cmdbuf[19] = readBuffer2->size;
|
||||
cmdbuf[20] = readBuffer2->transferOption;
|
||||
cmdbuf[21] = (u32) (readBuffer2->waitOperation & 0xFFFFFFFF);
|
||||
cmdbuf[22] = (u32) ((readBuffer2->waitOperation >> 32) & 0xFFFFFFFF);
|
||||
memcpy(&cmdbuf[23], footer->ptr, footer->size);
|
||||
cmdbuf[25] = footer->size;
|
||||
cmdbuf[26] = footer->transferOption;
|
||||
cmdbuf[27] = IPC_Desc_PXIBuffer(writeBuffer1->size, 0, true);
|
||||
cmdbuf[28] = (u32) writeBuffer1->ptr;
|
||||
cmdbuf[29] = IPC_Desc_PXIBuffer(writeBuffer2->size, 1, true);
|
||||
cmdbuf[30] = (u32) writeBuffer2->ptr;
|
||||
cmdbuf[31] = IPC_Desc_PXIBuffer(readBuffer1->size, 2, false);
|
||||
cmdbuf[32] = (u32) readBuffer1->ptr;
|
||||
cmdbuf[33] = IPC_Desc_PXIBuffer(readBuffer2->size, 3, false);
|
||||
cmdbuf[34] = (u32) readBuffer2->ptr;
|
||||
|
||||
if (R_FAILED(ret = svcSendSyncRequest(pxiDevHandle))) return ret;
|
||||
|
||||
return (Result)cmdbuf[1];
|
||||
}
|
||||
|
||||
Result PXIDEV_SPIWriteRead(u32* bytesRead, u64 initialWaitOperation, PXIDEV_SPIBuffer* writeBuffer, PXIDEV_SPIBuffer* readBuffer)
|
||||
{
|
||||
Result ret=0;
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0xE,10,4); // 0x000E0284
|
||||
cmdbuf[1] = (u32) (initialWaitOperation & 0xFFFFFFFF);
|
||||
cmdbuf[2] = (u32) ((initialWaitOperation >> 32) & 0xFFFFFFFF);
|
||||
cmdbuf[3] = writeBuffer->size;
|
||||
cmdbuf[4] = writeBuffer->transferOption;
|
||||
cmdbuf[5] = (u32) (writeBuffer->waitOperation & 0xFFFFFFFF);
|
||||
cmdbuf[6] = (u32) ((writeBuffer->waitOperation >> 32) & 0xFFFFFFFF);
|
||||
cmdbuf[7] = readBuffer->size;
|
||||
cmdbuf[8] = readBuffer->transferOption;
|
||||
cmdbuf[9] = (u32) (readBuffer->waitOperation & 0xFFFFFFFF);
|
||||
cmdbuf[10] = (u32) ((readBuffer->waitOperation >> 32) & 0xFFFFFFFF);
|
||||
cmdbuf[11] = IPC_Desc_PXIBuffer(writeBuffer->size, 0, true);
|
||||
cmdbuf[12] = (u32) writeBuffer->ptr;
|
||||
cmdbuf[13] = IPC_Desc_PXIBuffer(readBuffer->size, 1, false);
|
||||
cmdbuf[14] = (u32) readBuffer->ptr;
|
||||
|
||||
if (R_FAILED(ret = svcSendSyncRequest(pxiDevHandle))) return ret;
|
||||
|
||||
if (bytesRead) *bytesRead = cmdbuf[2];
|
||||
|
||||
return (Result)cmdbuf[1];
|
||||
}
|
@ -52,7 +52,7 @@ static Result sslcipc_Initialize(void)
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
static Result sslcipc_CreateContext(sslcContext *context, int sockfd, u32 input_opt, char *hostname)
|
||||
static Result sslcipc_CreateContext(sslcContext *context, int sockfd, u32 input_opt, const char *hostname)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
u32 size = strlen(hostname)+1;
|
||||
@ -101,7 +101,7 @@ static Result sslcipc_DestroyCertChain(u32 type, u32 contexthandle)
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
static Result sslcipc_CertChainAddCert(u32 type, u32 contexthandle, u8 *cert, u32 certsize, u32 *cert_contexthandle)
|
||||
static Result sslcipc_CertChainAddCert(u32 type, u32 contexthandle, const u8 *cert, u32 certsize, u32 *cert_contexthandle)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -151,7 +151,7 @@ static Result sslcipc_CertChainRemoveCert(u32 type, u32 contexthandle, u32 cert_
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result sslcOpenClientCertContext(u8 *cert, u32 certsize, u8 *key, u32 keysize, u32 *ClientCert_contexthandle)
|
||||
Result sslcOpenClientCertContext(const u8 *cert, u32 certsize, const u8 *key, u32 keysize, u32 *ClientCert_contexthandle)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -275,7 +275,7 @@ static Result sslcipc_StartConnectionGetOut(sslcContext *context, int *internal_
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Result sslcipc_DataTransfer(sslcContext *context, void *buf, size_t len, u32 type)
|
||||
static Result sslcipc_DataTransfer(sslcContext *context, const void *buf, size_t len, u32 type)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -378,7 +378,7 @@ static Result sslcipc_ContextInitSharedmem(sslcContext *context, u32 size)
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result sslcAddCert(sslcContext *context, u8 *buf, u32 size)
|
||||
Result sslcAddCert(sslcContext *context, const u8 *buf, u32 size)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
@ -405,7 +405,7 @@ Result sslcDestroyRootCertChain(u32 RootCertChain_contexthandle)
|
||||
return sslcipc_DestroyCertChain(0, RootCertChain_contexthandle);
|
||||
}
|
||||
|
||||
Result sslcAddTrustedRootCA(u32 RootCertChain_contexthandle, u8 *cert, u32 certsize, u32 *cert_contexthandle)
|
||||
Result sslcAddTrustedRootCA(u32 RootCertChain_contexthandle, const u8 *cert, u32 certsize, u32 *cert_contexthandle)
|
||||
{
|
||||
return sslcipc_CertChainAddCert(0, RootCertChain_contexthandle, cert, certsize, cert_contexthandle);
|
||||
}
|
||||
@ -430,7 +430,7 @@ Result sslcDestroy8CertChain(u32 PinnedCertChain_contexthandle)
|
||||
return sslcipc_DestroyCertChain(1, PinnedCertChain_contexthandle);
|
||||
}
|
||||
|
||||
Result sslc8CertChainAddCert(u32 PinnedCertChain_contexthandle, u8 *cert, u32 certsize, u32 *cert_contexthandle)
|
||||
Result sslc8CertChainAddCert(u32 PinnedCertChain_contexthandle, const u8 *cert, u32 certsize, u32 *cert_contexthandle)
|
||||
{
|
||||
return sslcipc_CertChainAddCert(1, PinnedCertChain_contexthandle, cert, certsize, cert_contexthandle);
|
||||
}
|
||||
@ -445,7 +445,7 @@ Result sslc8CertChainRemoveCert(u32 PinnedCertChain_contexthandle, u32 cert_cont
|
||||
return sslcipc_CertChainRemoveCert(1, PinnedCertChain_contexthandle, cert_contexthandle);
|
||||
}
|
||||
|
||||
Result sslcCreateContext(sslcContext *context, int sockfd, u32 input_opt, char *hostname)
|
||||
Result sslcCreateContext(sslcContext *context, int sockfd, u32 input_opt, const char *hostname)
|
||||
{
|
||||
Result ret=0;
|
||||
|
||||
@ -507,7 +507,7 @@ Result sslcRead(sslcContext *context, void *buf, size_t len, bool peek)
|
||||
return sslcipc_DataTransfer(context, buf, len, type);
|
||||
}
|
||||
|
||||
Result sslcWrite(sslcContext *context, void *buf, size_t len)
|
||||
Result sslcWrite(sslcContext *context, const void *buf, size_t len)
|
||||
{
|
||||
return sslcipc_DataTransfer(context, buf, len, 2);
|
||||
}
|
||||
|
@ -481,7 +481,7 @@ Result udsScanBeacons(void *buf, size_t maxsize, udsNetworkScanInfo **networks,
|
||||
|
||||
if(maxsize < sizeof(nwmBeaconDataReplyHeader))return -2;
|
||||
|
||||
ret = svcCreateEvent(&event, 0);
|
||||
ret = svcCreateEvent(&event, RESET_ONESHOT);
|
||||
if(R_FAILED(ret))return ret;
|
||||
|
||||
if(!connected)ret = udsipc_RecvBeaconBroadcastData(outbuf, maxsize, &scaninput, wlancommID, id8, event);
|
||||
|
@ -352,6 +352,14 @@ SVC_BEGIN svcReplyAndReceive
|
||||
add sp, sp, #4
|
||||
bx lr
|
||||
|
||||
SVC_BEGIN svcBindInterrupt
|
||||
svc 0x50
|
||||
bx lr
|
||||
|
||||
SVC_BEGIN svcUnbindInterrupt
|
||||
svc 0x51
|
||||
bx lr
|
||||
|
||||
SVC_BEGIN svcInvalidateProcessDataCache
|
||||
svc 0x52
|
||||
bx lr
|
||||
|
@ -127,3 +127,92 @@ void RecursiveLock_Unlock(RecursiveLock* lock)
|
||||
LightLock_Unlock(&lock->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void LightEvent_SetState(LightEvent* event, int state)
|
||||
{
|
||||
do
|
||||
__ldrex(&event->state);
|
||||
while (__strex(&event->state, state));
|
||||
}
|
||||
|
||||
static inline int LightEvent_TryReset(LightEvent* event)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (__ldrex(&event->state))
|
||||
{
|
||||
__clrex();
|
||||
return 0;
|
||||
}
|
||||
} while (__strex(&event->state, -1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void LightEvent_Init(LightEvent* event, ResetType reset_type)
|
||||
{
|
||||
LightLock_Init(&event->lock);
|
||||
LightEvent_SetState(event, reset_type == RESET_STICKY ? -2 : -1);
|
||||
}
|
||||
|
||||
void LightEvent_Clear(LightEvent* event)
|
||||
{
|
||||
if (event->state == 1)
|
||||
{
|
||||
LightLock_Lock(&event->lock);
|
||||
LightEvent_SetState(event, -2);
|
||||
LightLock_Unlock(&event->lock);
|
||||
} else if (event->state == 0)
|
||||
LightEvent_SetState(event, -1);
|
||||
}
|
||||
|
||||
void LightEvent_Pulse(LightEvent* event)
|
||||
{
|
||||
if (event->state == -2)
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, -1, 0);
|
||||
else if (event->state == -1)
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, 1, 0);
|
||||
else
|
||||
LightEvent_Clear(event);
|
||||
}
|
||||
|
||||
void LightEvent_Signal(LightEvent* event)
|
||||
{
|
||||
if (event->state == -1)
|
||||
{
|
||||
LightEvent_SetState(event, 0);
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, 1, 0);
|
||||
} else if (event->state == -2)
|
||||
{
|
||||
LightLock_Lock(&event->lock);
|
||||
LightEvent_SetState(event, 1);
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, -1, 0);
|
||||
LightLock_Unlock(&event->lock);
|
||||
}
|
||||
}
|
||||
|
||||
int LightEvent_TryWait(LightEvent* event)
|
||||
{
|
||||
if (event->state == 1)
|
||||
return 1;
|
||||
return LightEvent_TryReset(event);
|
||||
}
|
||||
|
||||
void LightEvent_Wait(LightEvent* event)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (event->state == -2)
|
||||
{
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
|
||||
return;
|
||||
}
|
||||
if (event->state != -1)
|
||||
{
|
||||
if (event->state == 1)
|
||||
return;
|
||||
if (event->state == 0 && LightEvent_TryReset(event))
|
||||
return;
|
||||
}
|
||||
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user