/* main.c (De)initialization stuff. It's also here where sessions are being accepted. (c) TuxSH, 2016-2020 This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details). */ #include #include "PXI.h" #include "common.h" #include "MyThread.h" #include "receiver.h" #include "sender.h" Handle PXISyncInterrupt = 0, PXITransferMutex = 0; Handle terminationRequestedEvent = 0; bool shouldTerminate = false; SessionManager sessionManager = {0}; const char *serviceNames[10] = { "pxi:mc", "PxiFS0", "PxiFS1", "PxiFSB", "PxiFSR", "PxiPM", "pxi:dev", //in the official PXI module maxSessions(pxi:dev) == 2. It doesn't matter anyways, since srvSysRegisterService is always called with 1 "pxi:am9", "pxi:ps9", "pxi:srv11", }; const u32 nbStaticBuffersByService[10] = {0, 2, 2, 2, 2, 1, 4, 4, 4, 0}; u32 ALIGN(0x1000) staticBuffers[NB_STATIC_BUFFERS][0x400] = {{0}}; static inline void initPXI(void) { Result res; Handle handles[2] = {0}; PXIReset(); if(PXISyncInterrupt != 0) svcBreak(USERBREAK_PANIC); //0xE0A0183B assertSuccess(svcCreateEvent(&PXISyncInterrupt, RESET_ONESHOT)); if(PXITransferMutex != 0) svcBreak(USERBREAK_PANIC); //0xE0A0183B assertSuccess(svcCreateMutex(&PXITransferMutex, false)); assertSuccess(svcCreateEvent(&handles[0], RESET_ONESHOT)); //receive FIFO not empty assertSuccess(svcCreateEvent(&handles[1], RESET_ONESHOT)); //send FIFO empty assertSuccess(bindPXIInterrupts(&PXISyncInterrupt, &handles[0], &handles[1])); s32 handleIndex; do { while(!PXIIsSendFIFOFull()) PXISendWord(0); res = assertSuccess(svcWaitSynchronization(handles[0], 0LL)); if(R_DESCRIPTION(res) == RD_TIMEOUT) assertSuccess(svcWaitSynchronizationN(&handleIndex, handles, 2, false, -1LL)); else handleIndex = 0; } while(handleIndex != 0); unbindPXIInterrupts(NULL, &handles[0], &handles[1]); PXISendByte(1); while(PXIReceiveByte() < 1); while (!PXIIsReceiveFIFOEmpty()) PXIReceiveWord(); PXISendByte(2); while(PXIReceiveByte() < 2); svcCloseHandle(handles[0]); svcCloseHandle(handles[1]); } static inline void exitPXI(void) { unbindPXIInterrupts(&PXISyncInterrupt, NULL, NULL); svcCloseHandle(PXITransferMutex); svcCloseHandle(PXISyncInterrupt); PXIReset(); } static u8 ALIGN(8) receiverStack[THREAD_STACK_SIZE]; static u8 ALIGN(8) senderStack[THREAD_STACK_SIZE]; static u8 ALIGN(8) PXISRV11HandlerStack[THREAD_STACK_SIZE]; // this is called before main void __appInit() { assertSuccess(svcCreateEvent(&terminationRequestedEvent, RESET_STICKY)); assertSuccess(svcCreateEvent(&sessionManager.sendAllBuffersToArm9Event, RESET_ONESHOT)); assertSuccess(svcCreateSemaphore(&sessionManager.replySemaphore, 0, 9)); assertSuccess(svcCreateEvent(&sessionManager.PXISRV11CommandReceivedEvent, RESET_ONESHOT)); assertSuccess(svcCreateEvent(&sessionManager.PXISRV11ReplySentEvent, RESET_ONESHOT)); initPXI(); for(Result res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL)) { res = srvInit(); if(R_FAILED(res) && res != (Result)0xD88007FA) svcBreak(USERBREAK_PANIC); } } // this is called after main exits void __appExit() { srvExit(); exitPXI(); svcCloseHandle(terminationRequestedEvent); svcCloseHandle(sessionManager.sendAllBuffersToArm9Event); svcCloseHandle(sessionManager.replySemaphore); svcCloseHandle(sessionManager.PXISRV11CommandReceivedEvent); svcCloseHandle(sessionManager.PXISRV11ReplySentEvent); } // stubs for non-needed pre-main functions void __system_initSyscalls(){} Result __sync_init(void); Result __sync_fini(void); void __ctru_exit() { void __libc_fini_array(void); __libc_fini_array(); __appExit(); __sync_fini(); svcExitProcess(); } void initSystem() { void __libc_init_array(void); __sync_init(); __system_initSyscalls(); __appInit(); __libc_init_array(); } int main(void) { Handle handles[10] = {0}; //notification handle + service handles MyThread receiverThread = {0}, senderThread = {0}, PXISRV11HandlerThread = {0}; for(u32 i = 0; i < 9; i++) assertSuccess(srvRegisterService(handles + 1 + i, serviceNames[i], 1)); assertSuccess(MyThread_Create(&receiverThread, receiver, receiverStack, THREAD_STACK_SIZE, 0x2D, -2)); assertSuccess(MyThread_Create(&senderThread, sender, senderStack, THREAD_STACK_SIZE, 0x2D, -2)); assertSuccess(MyThread_Create(&PXISRV11HandlerThread, PXISRV11Handler, PXISRV11HandlerStack, THREAD_STACK_SIZE, 0x2D, -2)); assertSuccess(srvEnableNotification(&handles[0])); while(!shouldTerminate) { s32 index = 0; assertSuccess(svcWaitSynchronizationN(&index, handles, 10, false, -1LL)); if(index == 0) { u32 notificationId; assertSuccess(srvReceiveNotification(¬ificationId)); if(notificationId == 0x100) shouldTerminate = true; } else { Handle session = 0; SessionData *data = &sessionManager.sessionData[index - 1]; assertSuccess(svcAcceptSession(&session, handles[index])); RecursiveLock_Lock(&sessionManager.senderLock); if(data->handle != 0) svcBreak(USERBREAK_PANIC); data->handle = session; assertSuccess(svcSignalEvent(sessionManager.sendAllBuffersToArm9Event)); RecursiveLock_Unlock(&sessionManager.senderLock); } } u32 PXIMC_OnPXITerminate = 0x10000; //TODO: see if this is correct sessionManager.sessionData[0].state = STATE_SENT_TO_ARM9; sendPXICmdbuf(NULL, 0, &PXIMC_OnPXITerminate); assertSuccess(MyThread_Join(&receiverThread, -1LL)); assertSuccess(MyThread_Join(&senderThread, -1LL)); assertSuccess(MyThread_Join(&PXISRV11HandlerThread, -1LL)); for(u32 i = 0; i < 10; i++) svcCloseHandle(handles[i]); return 0; }