diff --git a/nx/include/switch/services/irs.h b/nx/include/switch/services/irs.h index 8c216922..ff0b0ab9 100644 --- a/nx/include/switch/services/irs.h +++ b/nx/include/switch/services/irs.h @@ -10,6 +10,45 @@ #include "../services/sm.h" #include "../services/hid.h" +typedef struct { + u64 unk_x0; + u8 unk_x8; + u8 unk_x9; + u8 unk_xa; + u8 pad[5]; + u16 unk_x10; + u32 unk_x12; + u16 unk_x16; + u32 unk_constant;//offset 0x18 + u8 unk_x1c; + u8 unk_x1d; + u8 pad2[2]; +} PACKED irsPackedMomentProcessorConfig; + +typedef struct { + u64 unk_x0; + u32 unk_x8; + u32 unk_xc; + u8 unk_x10; + u8 pad[7]; + u32 unk_x18; +} irsImageTransferProcessorConfig; + +typedef struct { + u64 unk_x0; + u8 unk_x8; + u8 unk_x9; + u8 unk_xa; + u8 pad[5]; + u32 unk_constant;//offset 0x10 + u8 unk_x14; + u8 pad2[3]; +} irsPackedImageTransferProcessorConfig; + +typedef struct { + u8 unk_x0[0x10]; +} PACKED irsImageTransferProcessorState; + Result irsInitialize(void); void irsExit(void); @@ -20,3 +59,24 @@ void* irsGetSharedmemAddr(void); Result irsActivateIrsensor(bool activate); Result irsGetIrCameraHandle(u32 *IrCameraHandle, HidControllerID id); + +/** + * @brief Start ImageTransferProcessor. + * @param[in] IrCameraHandle Camera handle. + * @param[in] config Input config. + * @param[in] size Work-buffer size, must be 0x1000-byte aligned. + * @note Do not use if already started. + */ +Result irsRunImageTransferProcessor(u32 IrCameraHandle, irsImageTransferProcessorConfig *config, size_t size); + +Result irsGetImageTransferProcessorState(u32 IrCameraHandle, void* buffer, size_t size, irsImageTransferProcessorState *state); + +/// Stop ImageTransferProcessor. Do not use if already stopped. +/// \ref irsExit calls this with all IrCameraHandles which were not already used with \ref irsStopImageProcessor. +Result irsStopImageProcessor(u32 IrCameraHandle); + +/// "Suspend" ImageTransferProcessor. +/// TODO: What does this really do? +Result irsSuspendImageProcessor(u32 IrCameraHandle); + +void irsGetDefaultImageTransferProcessorConfig(irsImageTransferProcessorConfig *config); diff --git a/nx/source/services/irs.c b/nx/source/services/irs.c index c395a861..51230972 100644 --- a/nx/source/services/irs.c +++ b/nx/source/services/irs.c @@ -7,10 +7,19 @@ #include "services/hid.h" #include "services/sm.h" #include "kernel/shmem.h" +#include "kernel/tmem.h" + +typedef struct { + bool initialized; + u32 IrCameraHandle; + TransferMemory transfermem; +} irsCameraEntry; static Service g_irsSrv; static SharedMemory g_irsSharedmem; -bool g_irsSensorActivated; +static bool g_irsSensorActivated; + +static irsCameraEntry g_irsCameras[8]; static Result _irsGetIrsensorSharedMemoryHandle(Handle* handle_out, u64 AppletResourceUserId); @@ -23,6 +32,9 @@ Result irsInitialize(void) Handle sharedmem_handle; u64 AppletResourceUserId=0; + g_irsSensorActivated = 0; + memset(g_irsCameras, 0, sizeof(g_irsCameras)); + rc = appletGetAppletResourceUserId(&AppletResourceUserId); if (R_FAILED(rc)) return rc; @@ -48,12 +60,75 @@ Result irsInitialize(void) void irsExit(void) { + int i; + size_t entrycount = sizeof(g_irsCameras)/sizeof(irsCameraEntry); + irsCameraEntry *entry; + + for(i=0; iinitialized) continue; + irsStopImageProcessor(entry->IrCameraHandle); + } + irsActivateIrsensor(0); serviceClose(&g_irsSrv); shmemClose(&g_irsSharedmem); } +static Result _irsCameraEntryAlloc(u32 IrCameraHandle, irsCameraEntry **out_entry) { + int i; + size_t entrycount = sizeof(g_irsCameras)/sizeof(irsCameraEntry); + int empty_entry = -1; + irsCameraEntry *entry; + + if (out_entry) *out_entry = NULL; + + for(i=0; iinitialized) { + if (entry->IrCameraHandle == IrCameraHandle) + return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized); + } + else if (empty_entry == -1) + empty_entry = i; + } + + if (empty_entry == -1) + return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized); + + entry = &g_irsCameras[empty_entry]; + + entry->initialized = 1; + entry->IrCameraHandle = IrCameraHandle; + + if (out_entry) *out_entry = entry; + + return 0; +} + +static Result _irsCameraEntryGet(u32 IrCameraHandle, irsCameraEntry **out_entry) { + int i; + size_t entrycount = sizeof(g_irsCameras)/sizeof(irsCameraEntry); + irsCameraEntry *entry; + *out_entry = NULL; + + for(i=0; iinitialized && entry->IrCameraHandle == IrCameraHandle) { + *out_entry = entry; + return 0; + } + } + + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); +} + +static void _irsCameraEntryFree(irsCameraEntry *entry) { + tmemClose(&entry->transfermem); + memset(entry, 0, sizeof(irsCameraEntry)); +} + Service* irsGetSessionService(void) { return &g_irsSrv; } @@ -147,6 +222,204 @@ static Result _irsGetIrsensorSharedMemoryHandle(Handle* handle_out, u64 AppletRe return rc; } +static Result _irsStopImageProcessor(u32 IrCameraHandle, u64 AppletResourceUserId) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 IrCameraHandle; + u64 AppletResourceUserId; + } *raw; + + ipcSendPid(&c); + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 305; + raw->IrCameraHandle = IrCameraHandle; + raw->AppletResourceUserId = AppletResourceUserId; + + Result rc = serviceIpcDispatch(&g_irsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result irsStopImageProcessor(u32 IrCameraHandle) { + Result rc=0; + u64 AppletResourceUserId=0; + irsCameraEntry *entry = NULL; + + if (!serviceIsActive(&g_irsSrv)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + rc = appletGetAppletResourceUserId(&AppletResourceUserId); + if (R_FAILED(rc)) + return rc; + + rc = _irsCameraEntryGet(IrCameraHandle, &entry); + if (R_FAILED(rc)) + return rc; + + if (entry->transfermem.handle == INVALID_HANDLE) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + rc = _irsStopImageProcessor(IrCameraHandle, AppletResourceUserId); + _irsCameraEntryFree(entry); + return rc; +} + +static Result _irsRunImageTransferProcessor(u32 IrCameraHandle, u64 AppletResourceUserId, irsPackedImageTransferProcessorConfig *config, Handle transfermem, u64 transfermem_size) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 IrCameraHandle; + u64 AppletResourceUserId; + irsPackedImageTransferProcessorConfig config; + u64 TransferMemory_size; + } *raw; + + ipcSendPid(&c); + ipcSendHandleCopy(&c, transfermem); + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 308; + raw->IrCameraHandle = IrCameraHandle; + raw->AppletResourceUserId = AppletResourceUserId; + raw->TransferMemory_size = transfermem_size; + + memcpy(&raw->config, config, sizeof(raw->config)); + + Result rc = serviceIpcDispatch(&g_irsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result irsRunImageTransferProcessor(u32 IrCameraHandle, irsImageTransferProcessorConfig *config, size_t size) { + Result rc=0; + u64 AppletResourceUserId=0; + irsCameraEntry *entry = NULL; + irsPackedImageTransferProcessorConfig packed_config; + + memset(&packed_config, 0, sizeof(packed_config)); + + packed_config.unk_x0 = config->unk_x0; + packed_config.unk_x8 = config->unk_x8; + packed_config.unk_x9 = config->unk_xc; + packed_config.unk_xa = config->unk_x10; + packed_config.unk_constant = 0xa0003; + packed_config.unk_x14 = config->unk_x18; + + rc = appletGetAppletResourceUserId(&AppletResourceUserId); + if (R_FAILED(rc)) + return rc; + + rc = _irsCameraEntryAlloc(IrCameraHandle, &entry); + if (R_FAILED(rc)) + return rc; + + rc = tmemCreate(&entry->transfermem, size, Perm_None); + if (R_FAILED(rc)) return rc; + + rc = _irsRunImageTransferProcessor(IrCameraHandle, AppletResourceUserId, &packed_config, entry->transfermem.handle, size); + + if (R_FAILED(rc)) _irsCameraEntryFree(entry); + + return rc; +} + +static Result _irsGetImageTransferProcessorState(u32 IrCameraHandle, u64 AppletResourceUserId, void* buffer, size_t size, irsImageTransferProcessorState *state) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 IrCameraHandle; + u64 AppletResourceUserId; + } *raw; + + ipcSendPid(&c); + ipcAddRecvBuffer(&c, buffer, size, 0); + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 309; + raw->IrCameraHandle = IrCameraHandle; + raw->AppletResourceUserId = AppletResourceUserId; + + Result rc = serviceIpcDispatch(&g_irsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + irsImageTransferProcessorState state; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && state) + memcpy(state, &resp->state, sizeof(irsImageTransferProcessorState)); + } + + return rc; +} + +Result irsGetImageTransferProcessorState(u32 IrCameraHandle, void* buffer, size_t size, irsImageTransferProcessorState *state) { + Result rc=0; + u64 AppletResourceUserId=0; + + rc = appletGetAppletResourceUserId(&AppletResourceUserId); + if (R_FAILED(rc)) + return rc; + + rc = _irsGetImageTransferProcessorState(IrCameraHandle, AppletResourceUserId, buffer, size, state); + return rc; +} + +void irsGetDefaultImageTransferProcessorConfig(irsImageTransferProcessorConfig *config) { + memset(config, 0, sizeof(irsImageTransferProcessorConfig)); + + config->unk_x0 = 0x493E0; + config->unk_xc = 0x8; +} + Result irsGetIrCameraHandle(u32 *IrCameraHandle, HidControllerID id) { IpcCommand c; ipcInitialize(&c); @@ -185,3 +458,52 @@ Result irsGetIrCameraHandle(u32 *IrCameraHandle, HidControllerID id) { return rc; } +static Result _irsSuspendImageProcessor(u32 IrCameraHandle, u64 AppletResourceUserId) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 IrCameraHandle; + u64 AppletResourceUserId; + } *raw; + + ipcSendPid(&c); + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 313; + raw->IrCameraHandle = IrCameraHandle; + raw->AppletResourceUserId = AppletResourceUserId; + + Result rc = serviceIpcDispatch(&g_irsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result irsSuspendImageProcessor(u32 IrCameraHandle) { + Result rc=0; + u64 AppletResourceUserId=0; + + rc = appletGetAppletResourceUserId(&AppletResourceUserId); + if (R_FAILED(rc)) + return rc; + + rc = _irsSuspendImageProcessor(IrCameraHandle, AppletResourceUserId); + return rc; +} +