mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-22 13:02:38 +02:00
nifm: Added support for IRequest.
This commit is contained in:
parent
d1f4b11f9a
commit
3c08ce6936
@ -8,6 +8,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
#include "../sf/service.h"
|
#include "../sf/service.h"
|
||||||
|
#include "../kernel/event.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NifmServiceType_User = 0, ///< Initializes nifm:u.
|
NifmServiceType_User = 0, ///< Initializes nifm:u.
|
||||||
@ -28,6 +29,25 @@ typedef enum {
|
|||||||
NifmInternetConnectionStatus_Connected = 4, ///< Internet is connected.
|
NifmInternetConnectionStatus_Connected = 4, ///< Internet is connected.
|
||||||
} NifmInternetConnectionStatus;
|
} NifmInternetConnectionStatus;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NifmRequestState_Invalid = 0, ///< Error.
|
||||||
|
NifmRequestState_Unknown1 = 1, ///< Not yet submitted or error.
|
||||||
|
NifmRequestState_OnHold = 2, ///< OnHold
|
||||||
|
NifmRequestState_Available = 3, ///< Available
|
||||||
|
NifmRequestState_Unknown4 = 4, ///< Unknown
|
||||||
|
NifmRequestState_Unknown5 = 5, ///< Unknown
|
||||||
|
} NifmRequestState;
|
||||||
|
|
||||||
|
/// Request
|
||||||
|
typedef struct {
|
||||||
|
Service s; ///< IRequest
|
||||||
|
Event event_request_state; ///< First Event from cmd GetSystemEventReadableHandles, autoclear=true. Signaled when the RequestState changes.
|
||||||
|
Event event1; ///< Second Event from cmd GetSystemEventReadableHandles.
|
||||||
|
|
||||||
|
NifmRequestState request_state; ///< \ref NifmRequestState from the GetRequestState cmd.
|
||||||
|
Result res; ///< Result from the GetResult cmd.
|
||||||
|
} NifmRequest;
|
||||||
|
|
||||||
/// ClientId
|
/// ClientId
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 id; ///< ClientId
|
u32 id; ///< ClientId
|
||||||
@ -140,6 +160,13 @@ Service* nifmGetServiceSession_GeneralService(void);
|
|||||||
*/
|
*/
|
||||||
NifmClientId nifmGetClientId(void);
|
NifmClientId nifmGetClientId(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CreateRequest
|
||||||
|
* @param[out] r \ref NifmRequest
|
||||||
|
* @param[in] autoclear Event autoclear to use for NifmRequest::event1, a default of true can be used for this.
|
||||||
|
*/
|
||||||
|
Result nifmCreateRequest(NifmRequest* r, bool autoclear);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief GetCurrentNetworkProfile
|
* @brief GetCurrentNetworkProfile
|
||||||
* @param[out] profile \ref NifmNetworkProfileData
|
* @param[out] profile \ref NifmNetworkProfileData
|
||||||
@ -201,3 +228,46 @@ bool nifmIsAnyInternetRequestAccepted(NifmClientId id);
|
|||||||
Result nifmIsAnyForegroundRequestAccepted(bool* out);
|
Result nifmIsAnyForegroundRequestAccepted(bool* out);
|
||||||
Result nifmPutToSleep(void);
|
Result nifmPutToSleep(void);
|
||||||
Result nifmWakeUp(void);
|
Result nifmWakeUp(void);
|
||||||
|
|
||||||
|
///@name IRequest
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Close a \ref NifmRequest.
|
||||||
|
* @param r \ref NifmRequest
|
||||||
|
*/
|
||||||
|
void nifmRequestClose(NifmRequest* r);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GetRequestState
|
||||||
|
* @param r \ref NifmRequest
|
||||||
|
* @param[out] out \ref NifmRequestState
|
||||||
|
*/
|
||||||
|
Result nifmGetRequestState(NifmRequest* r, NifmRequestState *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GetResult
|
||||||
|
* @param r \ref NifmRequest
|
||||||
|
*/
|
||||||
|
Result nifmGetResult(NifmRequest* r);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cancel
|
||||||
|
* @param r \ref NifmRequest
|
||||||
|
*/
|
||||||
|
Result nifmRequestCancel(NifmRequest* r);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Submit
|
||||||
|
* @param r \ref NifmRequest
|
||||||
|
*/
|
||||||
|
Result nifmRequestSubmit(NifmRequest* r);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SubmitAndWait
|
||||||
|
* @param r \ref NifmRequest
|
||||||
|
*/
|
||||||
|
Result nifmRequestSubmitAndWait(NifmRequest* r);
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ static Service g_nifmIGS;
|
|||||||
static Result _nifmCreateGeneralService(Service* srv_out);
|
static Result _nifmCreateGeneralService(Service* srv_out);
|
||||||
static Result _nifmCreateGeneralServiceOld(Service* srv_out);
|
static Result _nifmCreateGeneralServiceOld(Service* srv_out);
|
||||||
|
|
||||||
|
static Result _nifmRequestGetSystemEventReadableHandles(NifmRequest* r, bool autoclear);
|
||||||
|
|
||||||
NX_GENERATE_SERVICE_GUARD_PARAMS(nifm, (NifmServiceType service_type), (service_type));
|
NX_GENERATE_SERVICE_GUARD_PARAMS(nifm, (NifmServiceType service_type), (service_type));
|
||||||
|
|
||||||
Result _nifmInitialize(NifmServiceType service_type) {
|
Result _nifmInitialize(NifmServiceType service_type) {
|
||||||
@ -83,6 +85,11 @@ static Result _nifmCmdNoInOutBool(Service* srv, bool *out, u32 cmd_id) {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Result _nifmCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
|
||||||
|
serviceAssumeDomain(srv);
|
||||||
|
return serviceDispatchOut(srv, cmd_id, *out);
|
||||||
|
}
|
||||||
|
|
||||||
static Result _nifmCmdInU8NoOut(Service* srv, u8 inval, u64 cmd_id) {
|
static Result _nifmCmdInU8NoOut(Service* srv, u8 inval, u64 cmd_id) {
|
||||||
serviceAssumeDomain(srv);
|
serviceAssumeDomain(srv);
|
||||||
return serviceDispatchIn(srv, cmd_id, inval);
|
return serviceDispatchIn(srv, cmd_id, inval);
|
||||||
@ -162,6 +169,38 @@ NifmClientId nifmGetClientId(void) {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Result _nifmCreateRequest(Service* srv_out, s32 inval) {
|
||||||
|
serviceAssumeDomain(&g_nifmIGS);
|
||||||
|
return serviceDispatchIn(&g_nifmIGS, 4, inval,
|
||||||
|
.out_num_objects = 1,
|
||||||
|
.out_objects = srv_out,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result nifmCreateRequest(NifmRequest* r, bool autoclear) {
|
||||||
|
Result rc=0;
|
||||||
|
|
||||||
|
memset(r, 0, sizeof(*r));
|
||||||
|
|
||||||
|
rc = _nifmCreateRequest(&r->s, 0x2);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
rc = _nifmRequestGetSystemEventReadableHandles(r, autoclear);
|
||||||
|
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
serviceAssumeDomain(&r->s);
|
||||||
|
serviceClose(&r->s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
r->request_state = NifmRequestState_Unknown1;
|
||||||
|
r->res = MAKERESULT(110, 311);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
Result nifmGetCurrentNetworkProfile(NifmNetworkProfileData *profile) {
|
Result nifmGetCurrentNetworkProfile(NifmNetworkProfileData *profile) {
|
||||||
NifmSfNetworkProfileData tmp={0};
|
NifmSfNetworkProfileData tmp={0};
|
||||||
serviceAssumeDomain(&g_nifmIGS);
|
serviceAssumeDomain(&g_nifmIGS);
|
||||||
@ -274,3 +313,119 @@ Result nifmPutToSleep(void) {
|
|||||||
Result nifmWakeUp(void) {
|
Result nifmWakeUp(void) {
|
||||||
return _nifmCmdNoIO(&g_nifmIGS, 24);
|
return _nifmCmdNoIO(&g_nifmIGS, 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IRequest
|
||||||
|
|
||||||
|
void nifmRequestClose(NifmRequest* r) {
|
||||||
|
eventClose(&r->event1);
|
||||||
|
eventClose(&r->event_request_state);
|
||||||
|
|
||||||
|
serviceAssumeDomain(&r->s);
|
||||||
|
serviceClose(&r->s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result _nifmRequestGetSystemEventReadableHandles(NifmRequest* r, bool autoclear) {
|
||||||
|
Result rc=0;
|
||||||
|
Handle tmp_handles[2] = {INVALID_HANDLE, INVALID_HANDLE};
|
||||||
|
|
||||||
|
serviceAssumeDomain(&r->s);
|
||||||
|
rc = serviceDispatch(&r->s, 2,
|
||||||
|
.out_handle_attrs = { SfOutHandleAttr_HipcCopy, SfOutHandleAttr_HipcCopy },
|
||||||
|
.out_handles = tmp_handles,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
eventLoadRemote(&r->event_request_state, tmp_handles[0], true);
|
||||||
|
eventLoadRemote(&r->event1, tmp_handles[1], autoclear);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _nifmUpdateState(NifmRequest* r) {
|
||||||
|
Result rc=0;
|
||||||
|
u32 tmp=0;
|
||||||
|
|
||||||
|
rc = _nifmCmdNoInOutU32(&r->s, &tmp, 0); // GetRequestState
|
||||||
|
r->request_state = R_SUCCEEDED(rc) ? tmp : 0; // sdknso ignores error other than this.
|
||||||
|
|
||||||
|
rc = _nifmCmdNoIO(&r->s, 1); // GetResult
|
||||||
|
r->res = rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result nifmGetRequestState(NifmRequest* r, NifmRequestState *out) {
|
||||||
|
if (!serviceIsActive(&r->s))
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||||
|
|
||||||
|
if (R_FAILED(eventWait(&r->event_request_state, 0))) {
|
||||||
|
if (out) *out = r->request_state;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sdknso would clear the event here, but it's autoclear anyway.
|
||||||
|
|
||||||
|
_nifmUpdateState(r);
|
||||||
|
if (out) *out = r->request_state;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result nifmGetResult(NifmRequest* r) {
|
||||||
|
if (!serviceIsActive(&r->s))
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||||
|
|
||||||
|
if (R_FAILED(eventWait(&r->event_request_state, 0))) return r->res;
|
||||||
|
|
||||||
|
// sdknso would clear the event here, but it's autoclear anyway.
|
||||||
|
|
||||||
|
_nifmUpdateState(r);
|
||||||
|
return r->res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result nifmRequestCancel(NifmRequest* r) {
|
||||||
|
if (!serviceIsActive(&r->s))
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||||
|
|
||||||
|
return _nifmCmdNoIO(&r->s, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result nifmRequestSubmit(NifmRequest* r) {
|
||||||
|
Result rc=0;
|
||||||
|
NifmRequestState tmp;
|
||||||
|
|
||||||
|
if (!serviceIsActive(&r->s))
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||||
|
|
||||||
|
rc = nifmGetRequestState(r, &tmp);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && (tmp == NifmRequestState_Unknown1 || tmp == NifmRequestState_OnHold || tmp == NifmRequestState_Available || tmp == NifmRequestState_Unknown5)) {
|
||||||
|
_nifmCmdNoIO(&r->s, 4); // Submit (sdknso ignores error)
|
||||||
|
_nifmUpdateState(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result nifmRequestSubmitAndWait(NifmRequest* r) {
|
||||||
|
Result rc=0;
|
||||||
|
NifmRequestState tmp;
|
||||||
|
|
||||||
|
rc = nifmRequestSubmit(r);
|
||||||
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
rc = nifmGetRequestState(r, &tmp);
|
||||||
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
|
if (tmp != NifmRequestState_OnHold) return rc;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(eventWait(&r->event_request_state, 10000000000ULL))) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sdknso would clear the event here, but it's autoclear anyway.
|
||||||
|
|
||||||
|
_nifmUpdateState(r);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user