From 8c656065a41d7c7ee558a59fc19a1f7817e19050 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Tue, 20 May 2014 15:49:03 -0400 Subject: [PATCH] Implemented more APT and GSPGPU commands. Improved return-to-menu handling, screenshots for the suspended application are now handled as well. Implemented power-button handling, and implemented sleep-mode handling. Updated the example apps for the APT changes, and fixed other issues with the examples. --- arm11u/Makefile | 2 +- arm11u/source/crt0.s | 2 +- arm11u/source/main.c | 8 ++ gpu/Makefile | 4 +- gpu/source/crt0.s | 2 +- gpu/source/main.c | 8 ++ libctru/include/ctr/APT.h | 12 +- libctru/include/ctr/GSP.h | 16 +++ libctru/source/APT.c | 231 ++++++++++++++++++++++++++++++++++++-- libctru/source/GSP.c | 46 ++++++++ sdmc/Makefile | 7 +- sdmc/source/crt0.s | 2 +- sdmc/source/main.c | 30 +++-- 13 files changed, 342 insertions(+), 28 deletions(-) diff --git a/arm11u/Makefile b/arm11u/Makefile index 8f02861..ca643f4 100644 --- a/arm11u/Makefile +++ b/arm11u/Makefile @@ -1,7 +1,7 @@ CC = arm-none-eabi-gcc LINK = arm-none-eabi-ld OBJCOPY = arm-none-eabi-objcopy -CTRULIB = "../libctru" +CTRULIB = ../libctru CFLAGS += -Wall -std=c99 -march=armv6 -O3 -I"$(CTRULIB)/include" -I$(DEVKITPRO)/libnds/include LDFLAGS += --script=ccd00.ld -L"$(DEVKITARM)/arm-none-eabi/lib" -L"$(CTRULIB)/lib" diff --git a/arm11u/source/crt0.s b/arm11u/source/crt0.s index 6463bc2..557c327 100644 --- a/arm11u/source/crt0.s +++ b/arm11u/source/crt0.s @@ -1,4 +1,4 @@ -.section ".text" +.section ".init" .arm .align 4 .global _init diff --git a/arm11u/source/main.c b/arm11u/source/main.c index 027a117..6cc7f83 100644 --- a/arm11u/source/main.c +++ b/arm11u/source/main.c @@ -139,6 +139,14 @@ int main() swapBuffers(); copyBuffer(); } + else if(status == APP_SUSPENDING) + { + aptReturnToMenu(); + } + else if(status == APP_SLEEPMODE) + { + aptWaitStatusEvent(); + } svc_sleepThread(16666666); } diff --git a/gpu/Makefile b/gpu/Makefile index 6591a65..4840710 100644 --- a/gpu/Makefile +++ b/gpu/Makefile @@ -2,8 +2,8 @@ CC = arm-none-eabi-gcc LINK = arm-none-eabi-gcc AS = arm-none-eabi-as OBJCOPY = arm-none-eabi-objcopy -CTRULIB = "../libctru" -AEMSTROPATH = "../../aemstro" +CTRULIB = ../libctru +AEMSTROPATH = ../../aemstro CFLAGS += -Wall -std=c99 -march=armv6 -O3 -I"$(CTRULIB)/include" -I$(DEVKITPRO)/libnds/include # LDFLAGS += --script=ccd00.ld -L"$(DEVKITARM)/arm-none-eabi/lib" -L"$(DEVKITARM)/lib/gcc/arm-none-eabi/4.7.1" -L"$(CTRULIB)/lib" # LDFLAGS += --script=ccd00.ld -L"$(DEVKITARM)/arm-none-eabi/lib" -L"$(CTRULIB)/lib" diff --git a/gpu/source/crt0.s b/gpu/source/crt0.s index 6463bc2..557c327 100644 --- a/gpu/source/crt0.s +++ b/gpu/source/crt0.s @@ -1,4 +1,4 @@ -.section ".text" +.section ".init" .arm .align 4 .global _init diff --git a/gpu/source/main.c b/gpu/source/main.c index b8bb001..097e09b 100644 --- a/gpu/source/main.c +++ b/gpu/source/main.c @@ -128,6 +128,14 @@ int main() swapBuffers(); } + else if(status == APP_SUSPENDING) + { + aptReturnToMenu(); + } + else if(status == APP_SLEEPMODE) + { + aptWaitStatusEvent(); + } svc_sleepThread(16666666); } diff --git a/libctru/include/ctr/APT.h b/libctru/include/ctr/APT.h index 06a24f9..a5c2e94 100644 --- a/libctru/include/ctr/APT.h +++ b/libctru/include/ctr/APT.h @@ -9,9 +9,12 @@ typedef enum{ }NS_APPID; // cf http://3dbrew.org/wiki/NS#AppIDs typedef enum{ + APT_NOTINITIALIZED, APP_RUNNING, APP_SUSPENDED, - APP_EXITING + APP_EXITING, + APP_SUSPENDING, + APP_SLEEPMODE }APP_STATUS; extern Handle aptEvents[3]; @@ -23,6 +26,10 @@ void aptCloseSession(); void aptSetupEventHandler(); void aptSetStatus(APP_STATUS status); APP_STATUS aptGetStatus(); +u32 aptGetStatusPower();//This can be used when the status is APP_SUSPEND* to check how the return-to-menu was triggered: 0 = home-button, 1 = power-button. +void aptSetStatusPower(u32 status); +void aptReturnToMenu();//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 aptWaitStatusEvent(); Result APT_GetLockHandle(Handle* handle, u16 flags, Handle* lockHandle); Result APT_Initialize(Handle* handle, NS_APPID appId, Handle* eventHandle1, Handle* eventHandle2); @@ -34,7 +41,10 @@ Result APT_NotifyToWait(Handle* handle, NS_APPID appID); Result APT_AppletUtility(Handle* handle, u32* out, u32 a, u32 size1, u8* buf1, u32 size2, u8* buf2); Result APT_GlanceParameter(Handle* handle, NS_APPID appID, u32 bufferSize, u32* buffer, u32* actualSize, u8* signalType); Result APT_ReceiveParameter(Handle* handle, NS_APPID appID, u32 bufferSize, u32* buffer, u32* actualSize, u8* signalType); +Result APT_SendParameter(Handle* handle, NS_APPID src_appID, NS_APPID dst_appID, u32 bufferSize, u32* buffer, Handle paramhandle, u8 signalType); +Result APT_SendCaptureBufferInfo(Handle* handle, u32 bufferSize, u32* buffer); Result APT_ReplySleepQuery(Handle* handle, NS_APPID appID, u32 a); +Result APT_ReplySleepNotificationComplete(Handle* handle, NS_APPID appID); Result APT_PrepareToCloseApplication(Handle* handle, u8 a); Result APT_CloseApplication(Handle* handle, u32 a, u32 b, u32 c); diff --git a/libctru/include/ctr/GSP.h b/libctru/include/ctr/GSP.h index 3b16f2e..57f3cdf 100644 --- a/libctru/include/ctr/GSP.h +++ b/libctru/include/ctr/GSP.h @@ -14,11 +14,27 @@ typedef struct u32 unk;//"?" } GSP_FramebufferInfo; +typedef struct//See this for GSP_CaptureInfoEntry and GSP_CaptureInfo: http://3dbrew.org/wiki/GSPGPU:ImportDisplayCaptureInfo +{ + u32 *framebuf0_vaddr; + u32 *framebuf1_vaddr; + u32 format; + u32 framebuf_widthbytesize; +} GSP_CaptureInfoEntry; + +typedef struct +{ + GSP_CaptureInfoEntry screencapture[2]; +} GSP_CaptureInfo; + Result gspInit(); void gspExit(); Result GSPGPU_AcquireRight(Handle *handle, u8 flags); Result GSPGPU_ReleaseRight(Handle *handle); +Result GSPGPU_ImportDisplayCaptureInfo(Handle* handle, GSP_CaptureInfo *captureinfo); +Result GSPGPU_SaveVramSysArea(Handle* handle); +Result GSPGPU_RestoreVramSysArea(Handle* handle); Result GSPGPU_SetLcdForceBlack(Handle *handle, u8 flags); Result GSPGPU_SetBufferSwap(Handle* handle, u32 screenid, GSP_FramebufferInfo *framebufinfo); Result GSPGPU_FlushDataCache(Handle *handle, u8* adr, u32 size); diff --git a/libctru/source/APT.c b/libctru/source/APT.c index 63ece7f..e9ccdfd 100644 --- a/libctru/source/APT.c +++ b/libctru/source/APT.c @@ -19,13 +19,117 @@ Handle aptEventHandlerThread; u64 aptEventHandlerStack[APT_HANDLER_STACKSIZE/8]; //u64 so that it's 8-byte aligned Handle aptStatusMutex; -u32 aptStatus; +Handle aptStatusEvent = 0; +u32 aptStatus = APT_NOTINITIALIZED; +u32 aptStatusPower = 0; u32 aptParameters[0x1000/4]; //TEMP +void aptInitCaptureInfo(u32 *ns_capinfo) +{ + u32 tmp=0; + u32 main_pixsz, sub_pixsz; + GSP_CaptureInfo gspcapinfo; + + memset(&gspcapinfo, 0, sizeof(GSP_CaptureInfo)); + + GSPGPU_ImportDisplayCaptureInfo(NULL, &gspcapinfo); + + if(gspcapinfo.screencapture[0].framebuf0_vaddr != gspcapinfo.screencapture[1].framebuf0_vaddr)ns_capinfo[1] = 1; + + ns_capinfo[4] = gspcapinfo.screencapture[0].format & 0x7; + ns_capinfo[7] = gspcapinfo.screencapture[1].format & 0x7; + + if(ns_capinfo[4] < 2) + { + main_pixsz = 3; + } + else + { + main_pixsz = 2; + } + + if(ns_capinfo[7] < 2) + { + sub_pixsz = 3; + } + else + { + sub_pixsz = 2; + } + + ns_capinfo[2] = sub_pixsz * 0x14000; + ns_capinfo[3] = ns_capinfo[2]; + + if(ns_capinfo[1])ns_capinfo[3] = main_pixsz * 0x19000 + ns_capinfo[2]; + + tmp = main_pixsz * 0x19000 + ns_capinfo[3]; + ns_capinfo[0] = main_pixsz * 0x7000 + tmp; +} + +void aptWaitStatusEvent() +{ + svc_waitSynchronization1(aptStatusEvent, U64_MAX); + svc_clearEvent(aptStatusEvent); +} + +void aptReturnToMenu() +{ + u32 tmp0 = 1, tmp1 = 0; + u32 ns_capinfo[0x20>>2]; + u32 tmp_params[0x20>>2]; + + /*aptOpenSession(); + APT_AppletUtility(NULL, NULL, 0x6, 0x4, (u8*)&tmp0, 0x1, (u8*)&tmp1); + aptCloseSession();*/ + + aptOpenSession(); + APT_PrepareToJumpToHomeMenu(NULL); //prepare for return to menu + aptCloseSession(); + + svc_clearEvent(aptStatusEvent); + aptSetStatus(APP_SUSPENDED); + + GSPGPU_SaveVramSysArea(NULL); + + memset(tmp_params, 0, 0x20); + memset(ns_capinfo, 0, 0x20); + + aptInitCaptureInfo(ns_capinfo); + + aptOpenSession(); + APT_SendParameter(NULL, currentAppId, 0x101, 0x20, ns_capinfo, 0x0, 0x10); + aptCloseSession(); + + aptOpenSession(); + APT_SendCaptureBufferInfo(NULL, 0x20, ns_capinfo); + aptCloseSession(); + + GSPGPU_ReleaseRight(NULL); //disable GSP module access + + aptOpenSession(); + APT_JumpToHomeMenu(NULL, 0x0, 0x0, 0x0); //jump ! + aptCloseSession(); + + aptOpenSession(); + APT_NotifyToWait(NULL, currentAppId); + aptCloseSession(); + + if(aptGetStatusPower()==0)//This is only executed when ret-to-menu was triggered via the home-button, not the power-button. + { + tmp0 = 0; + aptOpenSession(); + APT_AppletUtility(NULL, NULL, 0x4, 0x1, (u8*)&tmp0, 0x1, (u8*)&tmp1); + aptCloseSession(); + } + + aptWaitStatusEvent(); +} + void aptEventHandler(u32 arg) { bool runThread=true; + while(runThread) { s32 syncedID=0x0; @@ -45,18 +149,37 @@ void aptEventHandler(u32 arg) switch(signalType) { case 0x1: //home menu button got pressed - aptOpenSession(); - APT_PrepareToJumpToHomeMenu(NULL); //prepare for return to menu - aptCloseSession(); + case 0x8: //power button got pressed + if(aptGetStatus()==APP_RUNNING) + { + aptOpenSession(); + APT_ReplySleepQuery(NULL, currentAppId, 0x0); + aptCloseSession(); - aptSetStatus(APP_SUSPENDED); - - GSPGPU_ReleaseRight(NULL); //disable GSP module access - + if(signalType==0x1)aptSetStatusPower(0); + if(signalType==0x8)aptSetStatusPower(1); + aptSetStatus(APP_SUSPENDING);//The main thread should call aptReturnToMenu() when the status gets set to this. + } + + break; + + case 0x3: //preparing to enter sleep-mode aptOpenSession(); - APT_JumpToHomeMenu(NULL, 0x0, 0x0, 0x0); //jump ! + APT_ReplySleepQuery(NULL, currentAppId, 0x1); aptCloseSession(); break; + + case 0x5: //entering sleep-mode + aptOpenSession(); + APT_ReplySleepNotificationComplete(NULL, currentAppId); + aptCloseSession(); + aptSetStatus(APP_SLEEPMODE); + break; + + case 0x6: //leaving sleep-mode + GSPGPU_SetLcdForceBlack(NULL, 0); + aptSetStatus(APP_RUNNING); + break; } } break; @@ -73,6 +196,7 @@ void aptEventHandler(u32 arg) break; case 0xB: //just returned from menu GSPGPU_AcquireRight(NULL, 0x0); + GSPGPU_RestoreVramSysArea(NULL); aptSetStatus(APP_RUNNING); break; case 0xC: //exiting application @@ -116,6 +240,8 @@ Result aptInit(NS_APPID appID) aptOpenSession(); if((ret=APT_NotifyToWait(NULL, currentAppId)))return ret; aptCloseSession(); + + svc_createEvent(&aptStatusEvent, 0); return 0; } @@ -153,6 +279,7 @@ void aptExit() svc_closeHandle(aptStatusMutex); // svc_closeHandle(aptLockHandle); + svc_closeHandle(aptStatusEvent); } void aptSetupEventHandler() @@ -185,6 +312,8 @@ void aptSetupEventHandler() aptStatus=0; svc_releaseMutex(aptStatusMutex); + aptSetStatus(APP_RUNNING); + //create thread for stuff handling APT events svc_createThread(&aptEventHandlerThread, aptEventHandler, 0x0, (u32*)(&aptEventHandlerStack[APT_HANDLER_STACKSIZE/8]), 0x31, 0xfffffffe); } @@ -200,8 +329,35 @@ APP_STATUS aptGetStatus() void aptSetStatus(APP_STATUS status) { + u32 prevstatus; + svc_waitSynchronization1(aptStatusMutex, U64_MAX); - aptStatus=status; + + prevstatus = status; + aptStatus = status; + + if(prevstatus!=APT_NOTINITIALIZED) + { + if(status==APP_RUNNING)svc_signalEvent(aptStatusEvent); + if(status==APP_EXITING)svc_signalEvent(aptStatusEvent); + } + + svc_releaseMutex(aptStatusMutex); +} + +u32 aptGetStatusPower() +{ + u32 ret; + svc_waitSynchronization1(aptStatusMutex, U64_MAX); + ret=aptStatusPower; + svc_releaseMutex(aptStatusMutex); + return ret; +} + +void aptSetStatusPower(u32 status) +{ + svc_waitSynchronization1(aptStatusMutex, U64_MAX); + aptStatusPower = status; svc_releaseMutex(aptStatusMutex); } @@ -380,6 +536,47 @@ Result APT_ReceiveParameter(Handle* handle, NS_APPID appID, u32 bufferSize, u32* return cmdbuf[1]; } +Result APT_SendParameter(Handle* handle, NS_APPID src_appID, NS_APPID dst_appID, u32 bufferSize, u32* buffer, Handle paramhandle, u8 signalType) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + if(!handle)handle=&aptuHandle; + + cmdbuf[0] = 0x000C0104; //request header code + cmdbuf[1] = src_appID; + cmdbuf[2] = dst_appID; + cmdbuf[3] = signalType; + cmdbuf[4] = bufferSize; + + cmdbuf[5]=0x0; + cmdbuf[6] = paramhandle; + + cmdbuf[7] = (bufferSize<<14) | 2; + cmdbuf[8] = (u32)buffer; + + Result ret=0; + if((ret=svc_sendSyncRequest(*handle)))return ret; + + return cmdbuf[1]; +} + +Result APT_SendCaptureBufferInfo(Handle* handle, u32 bufferSize, u32* buffer) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + if(!handle)handle=&aptuHandle; + + cmdbuf[0] = 0x00400042; //request header code + cmdbuf[1] = bufferSize; + cmdbuf[2] = (bufferSize<<14) | 2; + cmdbuf[3] = (u32)buffer; + + Result ret=0; + if((ret=svc_sendSyncRequest(*handle)))return ret; + + return cmdbuf[1]; +} + Result APT_ReplySleepQuery(Handle* handle, NS_APPID appID, u32 a) { if(!handle)handle=&aptuHandle; @@ -395,6 +592,20 @@ Result APT_ReplySleepQuery(Handle* handle, NS_APPID appID, u32 a) return cmdbuf[1]; } +Result APT_ReplySleepNotificationComplete(Handle* handle, NS_APPID appID) +{ + if(!handle)handle=&aptuHandle; + + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x3F0040; //request header code + cmdbuf[1]=appID; + + Result ret=0; + if((ret=svc_sendSyncRequest(*handle)))return ret; + + return cmdbuf[1]; +} + Result APT_PrepareToCloseApplication(Handle* handle, u8 a) { if(!handle)handle=&aptuHandle; diff --git a/libctru/source/GSP.c b/libctru/source/GSP.c index ea557eb..a47acdd 100644 --- a/libctru/source/GSP.c +++ b/libctru/source/GSP.c @@ -47,6 +47,52 @@ Result GSPGPU_ReleaseRight(Handle* handle) return cmdbuf[1]; } +Result GSPGPU_ImportDisplayCaptureInfo(Handle* handle, GSP_CaptureInfo *captureinfo) +{ + if(!handle)handle=&gspGpuHandle; + + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x00180000; //request header code + + Result ret=0; + if((ret=svc_sendSyncRequest(*handle)))return ret; + + ret = cmdbuf[1]; + + if(ret==0) + { + memcpy(captureinfo, &cmdbuf[2], 0x20); + } + + return ret; +} + +Result GSPGPU_SaveVramSysArea(Handle* handle) +{ + if(!handle)handle=&gspGpuHandle; + + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x00190000; //request header code + + Result ret=0; + if((ret=svc_sendSyncRequest(*handle)))return ret; + + return cmdbuf[1]; +} + +Result GSPGPU_RestoreVramSysArea(Handle* handle) +{ + if(!handle)handle=&gspGpuHandle; + + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x001A0000; //request header code + + Result ret=0; + if((ret=svc_sendSyncRequest(*handle)))return ret; + + return cmdbuf[1]; +} + Result GSPGPU_SetLcdForceBlack(Handle* handle, u8 flags) { if(!handle)handle=&gspGpuHandle; diff --git a/sdmc/Makefile b/sdmc/Makefile index 4196b20..197fe4e 100644 --- a/sdmc/Makefile +++ b/sdmc/Makefile @@ -2,7 +2,7 @@ CC = arm-none-eabi-gcc LINK = arm-none-eabi-ld AS = arm-none-eabi-as OBJCOPY = arm-none-eabi-objcopy -CTRULIB = "../libctru" +CTRULIB = ../libctru CFLAGS += -Wall -std=c99 -march=armv6 -O3 -I"$(CTRULIB)/include" -I$(DEVKITPRO)/libnds/include LDFLAGS += --script=ccd00.ld -L"$(DEVKITARM)/arm-none-eabi/lib" -L"$(CTRULIB)/lib" @@ -28,7 +28,10 @@ endef .PHONY:=all -all: $(PROJECTNAME).bin +all: dir $(PROJECTNAME).bin + +dir: + @mkdir -p build ctrulib: cd $(CTRULIB) && make diff --git a/sdmc/source/crt0.s b/sdmc/source/crt0.s index 6463bc2..557c327 100644 --- a/sdmc/source/crt0.s +++ b/sdmc/source/crt0.s @@ -1,4 +1,4 @@ -.section ".text" +.section ".init" .arm .align 4 .global _init diff --git a/sdmc/source/main.c b/sdmc/source/main.c index b146328..0fbf9b8 100644 --- a/sdmc/source/main.c +++ b/sdmc/source/main.c @@ -137,20 +137,32 @@ int main() aptSetupEventHandler(); - while(!aptGetStatus()) + APP_STATUS status; + while((status=aptGetStatus())!=APP_EXITING) { - u32 PAD=hidSharedMem[7]; - renderEffect(); - swapBuffers(); - copyBuffer(); - u32 regData=PAD|0x01000000; - GSPGPU_WriteHWRegs(NULL, 0x202A04, ®Data, 4); - svc_sleepThread(1000000000); + if(status==APP_RUNNING) + { + u32 PAD=hidSharedMem[7]; + renderEffect(); + swapBuffers(); + copyBuffer(); + u32 regData=PAD|0x01000000; + GSPGPU_WriteHWRegs(NULL, 0x202A04, ®Data, 4); + svc_sleepThread(1000000000); + } + else if(status == APP_SUSPENDING) + { + aptReturnToMenu(); + } + else if(status == APP_SLEEPMODE) + { + aptWaitStatusEvent(); + } } svc_closeHandle(fsuHandle); hidExit(); - gspGpuInit(); + gspGpuExit(); aptExit(); svc_exitProcess(); return 0;