nifm: Added support for IRequest.

This commit is contained in:
yellows8 2020-05-12 23:32:20 -04:00
parent d1f4b11f9a
commit 3c08ce6936
No known key found for this signature in database
GPG Key ID: 0AF90DA3F1E60E43
2 changed files with 225 additions and 0 deletions

View File

@ -8,6 +8,7 @@
#pragma once
#include "../types.h"
#include "../sf/service.h"
#include "../kernel/event.h"
typedef enum {
NifmServiceType_User = 0, ///< Initializes nifm:u.
@ -28,6 +29,25 @@ typedef enum {
NifmInternetConnectionStatus_Connected = 4, ///< Internet is connected.
} 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
typedef struct {
u32 id; ///< ClientId
@ -140,6 +160,13 @@ Service* nifmGetServiceSession_GeneralService(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
* @param[out] profile \ref NifmNetworkProfileData
@ -201,3 +228,46 @@ bool nifmIsAnyInternetRequestAccepted(NifmClientId id);
Result nifmIsAnyForegroundRequestAccepted(bool* out);
Result nifmPutToSleep(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);
///@}

View File

@ -11,6 +11,8 @@ static Service g_nifmIGS;
static Result _nifmCreateGeneralService(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));
Result _nifmInitialize(NifmServiceType service_type) {
@ -83,6 +85,11 @@ static Result _nifmCmdNoInOutBool(Service* srv, bool *out, u32 cmd_id) {
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) {
serviceAssumeDomain(srv);
return serviceDispatchIn(srv, cmd_id, inval);
@ -162,6 +169,38 @@ NifmClientId nifmGetClientId(void) {
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) {
NifmSfNetworkProfileData tmp={0};
serviceAssumeDomain(&g_nifmIGS);
@ -274,3 +313,119 @@ Result nifmPutToSleep(void) {
Result nifmWakeUp(void) {
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;
}