diff --git a/gc/ogc/stm.h b/gc/ogc/stm.h index 71e9a2fa..8f606fa0 100644 --- a/gc/ogc/stm.h +++ b/gc/ogc/stm.h @@ -47,15 +47,36 @@ distribution. extern "C" { #endif /* __cplusplus */ +// There are also in conf.h anyways +enum STM_LedMode { + STM_LEDMODE_OFF, + STM_LEDMODE_DIM, + STM_LEDMODE_BRIGHT, +}; + +enum { + STM_MAX_LED_PATTERNS = 128, + + STM_LEDFLASH_USER = (1 << 0), + STM_LEDFLASH_NOEXEC = (1 << 1), + + STM_IDLEMODE_FAN_ON = (1 << 0), +}; + typedef void (*stmcallback)(u32 event); s32 __STM_Init(void); s32 __STM_Close(void); +stmcallback STM_RegisterEventHandler(stmcallback newhandler); + s32 STM_ShutdownToStandby(void); -s32 STM_ShutdownToIdle(void); -s32 STM_SetLedMode(u32 mode); +s32 STM_ShutdownToIdleEx(u32 flags); +#define STM_ShutdownToIdle() STM_ShutdownToIdleEx(0) s32 STM_RebootSystem(void); -stmcallback STM_RegisterEventHandler(stmcallback newhandler); + +s32 STM_SetLedMode(u32 mode); +s32 STM_StartLedFlashLoop(u8 pattern_id, u8 priority, u8 flags, const u16* patterns, u32 num_patterns); +s32 STM_VIDimming(bool enable, u32 luma, u32 chroma); #ifdef __cplusplus } diff --git a/libogc/stm.c b/libogc/stm.c index 90949a2f..18331b41 100644 --- a/libogc/stm.c +++ b/libogc/stm.c @@ -30,14 +30,21 @@ distribution. #if defined(HW_RVL) -#include +#include #include "ipc.h" #include "system.h" #include "asm.h" #include "processor.h" +#include "cache.h" #include "stm.h" //#define DEBUG_STM +#ifdef DEBUG_STM +#include +#define STM_printf(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS) +#else +#define STM_printf(...) while (0) {} +#endif #define IOCTL_STM_EVENTHOOK 0x1000 #define IOCTL_STM_GET_IDLEMODE 0x3001 @@ -63,8 +70,6 @@ static u32 __stm_ehclear= 0; static u32 __stm_ehbufin[0x08] ATTRIBUTE_ALIGN(32) = {0,0,0,0,0,0,0,0}; static u32 __stm_ehbufout[0x08] ATTRIBUTE_ALIGN(32) = {0,0,0,0,0,0,0,0}; -static u32 __stm_immbufin[0x08] ATTRIBUTE_ALIGN(32) = {0,0,0,0,0,0,0,0}; -static u32 __stm_immbufout[0x08] ATTRIBUTE_ALIGN(32) = {0,0,0,0,0,0,0,0}; static char __stm_eh_fs[] ATTRIBUTE_ALIGN(32) = "/dev/stm/eventhook"; static char __stm_imm_fs[] ATTRIBUTE_ALIGN(32) = "/dev/stm/immediate"; @@ -80,9 +85,8 @@ static vu16* const _viReg = (u16*)0xCC002000; s32 __STM_Init(void) { if(__stm_initialized==1) return 1; -#ifdef DEBUG_STM - printf("STM Init\n"); -#endif + + STM_printf("STM init"); __stm_vdinuse = 0; __stm_imm_fd = IOS_Open(__stm_imm_fs,0); @@ -91,9 +95,7 @@ s32 __STM_Init(void) __stm_eh_fd = IOS_Open(__stm_eh_fs,0); if(__stm_eh_fd<0) return 0; -#ifdef DEBUG_STM - printf("STM FDs: %d, %d\n",__stm_imm_fd, __stm_eh_fd); -#endif + STM_printf("STM FDs: %d, %d\n",__stm_imm_fd, __stm_eh_fd); __stm_initialized = 1; __STM_SetEventHook(); @@ -120,6 +122,13 @@ s32 __STM_Close(void) return ret; } +s32 __STM_SendCommand(s32 ioctl, const void *inbuf, u32 inlen, void *outbuf, u32 outlen) { + if (__stm_initialized == 0) + return STM_ENOTINIT; + + return IOS_Ioctl(__stm_imm_fd, ioctl, (void *)inbuf, inlen, outbuf, outlen); +} + s32 __STM_SetEventHook(void) { s32 ret; @@ -147,7 +156,7 @@ s32 __STM_ReleaseEventHook(void) __stm_ehclear = 1; - ret = IOS_Ioctl(__stm_imm_fd,IOCTL_STM_RELEASE_EH,__stm_immbufin,0x20,__stm_immbufout,0x20); + ret = __STM_SendCommand(IOCTL_STM_RELEASE_EH,NULL,0,NULL,0); if(ret>=0) __stm_ehregistered = 0; return ret; @@ -161,10 +170,8 @@ static s32 __STMEventHandler(s32 result,void *usrdata) return result; } -#ifdef DEBUG_STM - printf("STM Event: %08x\n",__stm_ehbufout[0]); -#endif - + STM_printf("STM Event: %08x\n",__stm_ehbufout[0]); + if(__stm_ehclear) { //release return 0; } @@ -186,53 +193,64 @@ stmcallback STM_RegisterEventHandler(stmcallback newhandler) return old; } +__attribute__((noreturn)) +static void WaitForImpendingDoom(void) { + u32 level; + _CPU_ISR_Disable(level); + ICFlashInvalidate(); + ppchalt(); +} + s32 STM_ShutdownToStandby(void) { int res; _viReg[1] = 0; if(__stm_initialized==0) { -#ifdef DEBUG_STM - printf("STM notinited\n"); -#endif + STM_printf("STM notinited\n"); return STM_ENOTINIT; } - __stm_immbufin[0] = 0; - res= IOS_Ioctl(__stm_imm_fd,IOCTL_STM_SHUTDOWN,__stm_immbufin,0x20,__stm_immbufout,0x20); + u32 config = 0; + res = __STM_SendCommand(IOCTL_STM_SHUTDOWN, &config, sizeof(u32), NULL, 0); if(res<0) { -#ifdef DEBUG_STM - printf("STM STBY failed: %d\n",res); -#endif + STM_printf("STM STBY failed: %d\n",res); } + + WaitForImpendingDoom(); return res; } -s32 STM_ShutdownToIdle(void) +s32 STM_ShutdownToIdleEx(u32 flags) { int res; + u32 config; _viReg[1] = 0; if(__stm_initialized==0) { -#ifdef DEBUG_STM - printf("STM notinited\n"); -#endif + STM_printf("STM notinited\n"); return STM_ENOTINIT; } switch(SYS_GetHollywoodRevision()) { case 0: case 1: case 2: - __stm_immbufin[0] = 0xFCA08280; + config = 0xFCA08280; break; default: - __stm_immbufin[0] = 0xFCE082C0; + config = 0xFCE082C0; + break; } - res= IOS_Ioctl(__stm_imm_fd,IOCTL_STM_IDLE,__stm_immbufin,0x20,__stm_immbufout,0x20); + + if (flags & STM_IDLEMODE_FAN_ON) { + config &= ~(1 << 30); + } + + res = __STM_SendCommand(IOCTL_STM_IDLE, &config, sizeof(u32), NULL, 0); if(res<0) { -#ifdef DEBUG_STM - printf("STM IDLE failed: %d\n",res); -#endif + STM_printf("STM IDLE failed: %d\n",res); } + + WaitForImpendingDoom(); return res; } @@ -240,17 +258,12 @@ s32 STM_SetLedMode(u32 mode) { int res; if(__stm_initialized==0) { -#ifdef DEBUG_STM - printf("STM notinited\n"); -#endif + STM_printf("STM notinited\n"); return STM_ENOTINIT; } - __stm_immbufin[0] = mode; - res= IOS_Ioctl(__stm_imm_fd,IOCTL_STM_LEDMODE,__stm_immbufin,0x20,__stm_immbufout,0x20); + res= __STM_SendCommand(IOCTL_STM_LEDMODE, &mode, sizeof(u32), NULL, 0); if(res<0) { -#ifdef DEBUG_STM - printf("STM LEDMODE failed: %d\n",res); -#endif + STM_printf("STM LEDMODE failed: %d\n",res); } return res; } @@ -261,21 +274,78 @@ s32 STM_RebootSystem(void) _viReg[1] = 0; if(__stm_initialized==0) { -#ifdef DEBUG_STM - printf("STM notinited\n"); -#endif + STM_printf("STM notinited\n"); return STM_ENOTINIT; } - __stm_immbufin[0] = 0; - res= IOS_Ioctl(__stm_imm_fd,IOCTL_STM_HOTRESET,__stm_immbufin,0x20,__stm_immbufout,0x20); + res= __STM_SendCommand(IOCTL_STM_HOTRESET, NULL, 0, NULL, 0); if(res<0) { -#ifdef DEBUG_STM - printf("STM HRST failed: %d\n",res); -#endif + STM_printf("STM HRST failed: %d\n",res); } + + WaitForImpendingDoom(); return res; } +struct STM_LedFlashConfig +{ + u32 : 8; + u32 flags : 8; + u32 priority : 8; + u32 pattern_id : 8; + + u16 patterns[STM_MAX_LED_PATTERNS]; +}; + +// capitalization of LED is debatable. libogc currently has STM_SetLedMode, meanwhile this function is internally called ISTM_StartLEDFlashLoop +s32 STM_StartLedFlashLoop(u8 pattern_id, u8 priority, u8 flags, const u16* patterns, u32 num_patterns) +{ + s32 ret; + struct STM_LedFlashConfig config = {}; + if ((flags & STM_LEDFLASH_USER) && patterns != NULL) { + if (num_patterns > STM_MAX_LED_PATTERNS) + num_patterns = STM_MAX_LED_PATTERNS; + + memcpy(config.patterns, patterns, sizeof(u16[num_patterns])); + } else { + num_patterns = 0; + flags &= ~STM_LEDFLASH_USER; + } + + config.pattern_id = pattern_id; + config.priority = priority; + config.flags = flags; + + ret = __STM_SendCommand(IOCTL_STM_LEDFLASH, &config, offsetof(struct STM_LedFlashConfig, patterns[num_patterns]), NULL, 0); + if (ret < 0) { + STM_printf("STM LEDFLASH failed: %d\n", ret); + } + + return ret; +} + +// This is where __stm_vdinuse would come into play +// https://github.com/koopthekoopa/wii-ipl/blob/main/libs/RVL_SDK/src/os/OSStateTM.c#L176 +// I guess it's to prevent the function from being called 0ms after it was called the first time. Not sure why. +s32 STM_VIDimming(bool enable, u32 luma, u32 chroma) +{ + s32 ret; + u32 inbuf[8]; + u32 outbuf[8]; + + inbuf[0] = (enable << 7) | (luma & 0x7) << 3 | (chroma & 0x7); + inbuf[1] = 0; + inbuf[2] = 0; + + inbuf[4] = 0; // keep nothing + inbuf[5] = ~0; // keep everything + inbuf[6] = ~0; // uses 0xFFFF0000 here, but, what is the register even for.... + ret = __STM_SendCommand(IOCTL_STM_VIDIMMING, inbuf, sizeof inbuf, outbuf, sizeof outbuf); + if (ret < 0) { + STM_printf("STM VIDIM failed: %d\n", ret); + } + + return ret; +} #endif /* defined(HW_RVL) */