29#define CDVDreg_PWOFF (*(volatile unsigned char*)0xBF402008)
31#define MAX_CALLBACKS 8
33#define MODNAME "Poweroff_Handler"
36#define M_PRINTF(format, args...) \
37 printf(MODNAME ": " format, ##args)
40#define M_DEBUG M_PRINTF
42#define M_DEBUG(format, args...)
49static void Shutdown();
50static void SendCmd(
void* data);
53typedef int (*intrhandler)(
void*);
55static intrhandler oldCdHandler=0;
66} CallbackTable[MAX_CALLBACKS];
70static char cmdData[16];
71static pwoffcb poweroff_button_cb = 0;
72static void *poweroff_button_data = 0;
75static int PowerOffThreadID = -1;
78static int myCdHandler(
void *param)
80 if (((CDVDreg_PWOFF & 1)==0) && (CDVDreg_PWOFF & 4))
85 M_DEBUG(
"Poweroff!!!! %08x\n", CDVDreg_PWOFF);
87 if (poweroff_button_cb)
88 poweroff_button_cb(poweroff_button_data);
91 return oldCdHandler(param);
94static void Shutdown(
void* data)
98 M_DEBUG(
"Shutdown\n");
101 for(i = MAX_CALLBACKS-1; i >= 0; i--)
103 if(CallbackTable[i].cb)
105 CallbackTable[i].cb(CallbackTable[i].data);
110 *((
unsigned char *)0xBF402017) = 0;
111 *((
unsigned char *)0xBF402016) = 0xF;
114static void SendCmd(
void* data)
118 iWakeupThread(PowerOffThreadID);
121static void PowerOffThread(
void *arg)
126 sceSifCallRpc(&client, POFF_RPC_BUTTON, 0, NULL, 0, NULL, 0, NULL, NULL);
129static void InitPowerOffThread(
void)
133 if(PowerOffThreadID < 0)
135 thread.thread = &PowerOffThread;
137 thread.option = PWROFF_IRX;
140 PowerOffThreadID = CreateThread(&
thread);
141 StartThread(PowerOffThreadID, NULL);
143 client.server = NULL;
144 while(sceSifBindRpc(&client, PWROFF_IRX, 0) < 0 || client.server == NULL) DelayThread(500);
152void SetPowerButtonHandler(pwoffcb func,
void* param)
154 poweroff_button_cb = func;
155 poweroff_button_data = param;
158void AddPowerOffHandler(pwoffcb func,
void* param)
162 for(i = 0; i < MAX_CALLBACKS; i++)
164 if(CallbackTable[i].cb == 0)
166 CallbackTable[i].cb = func;
167 CallbackTable[i].data = param;
168 M_DEBUG(
"Added callback at position %d\n", i);
173 if(i == MAX_CALLBACKS)
175 M_PRINTF(
"Could not add poweroff callback\n");
179void RemovePowerOffHandler(pwoffcb func)
183 for(i = 0; i < MAX_CALLBACKS; i++)
185 if(CallbackTable[i].cb == func)
191 if(i < MAX_CALLBACKS)
193 for(; i < (MAX_CALLBACKS-1); i++)
195 CallbackTable[i] = CallbackTable[i+1];
201void PoweroffShutdown()
206void* poweroff_rpc_server(
int fno,
void *data,
int size)
211 case PWROFF_SHUTDOWN:
215 case PWROFF_ENABLE_AUTO_SHUTOFF:
216 InitPowerOffThread();
220 SetPowerButtonHandler(Shutdown, 0);
222 SetPowerButtonHandler(SendCmd, 0);
229void poweroff_rpc_Thread(
void* param)
235 sceSifSetRpcQueue(&qd, GetThreadId());
236 sceSifRegisterRpc(&sd0, PWROFF_IRX, poweroff_rpc_server, cmdData, NULL, NULL, &qd);
240int _start(
int argc,
char *argv[])
248 if(RegisterLibraryEntries(&_exp_poweroff) != 0)
250 M_PRINTF(
"Poweroff already registered\n");
251 return MODULE_NO_RESIDENT_END;
254 SetPowerButtonHandler(Shutdown, 0);
256#pragma GCC diagnostic push
257#pragma GCC diagnostic ignored "-Warray-bounds"
258 if (handlers[IOP_IRQ_CDVD].handler==0) {
259 M_PRINTF(
"No CDROM handler. Run CDVDMAN first\n");
260 return MODULE_NO_RESIDENT_END;
263 if (((
int)handlers[IOP_IRQ_CDVD].handler & 3) != TYPE_C){
264 M_PRINTF(
"Cannot chain to non-C handler\n");
265 return MODULE_NO_RESIDENT_END;
268 oldCdHandler=(intrhandler)((
int)handlers[IOP_IRQ_CDVD].handler & ~3);
269 handlers[IOP_IRQ_CDVD].handler=(intrhandler)((
int)myCdHandler | TYPE_C);
270#pragma GCC diagnostic pop
272 memset(CallbackTable, 0,
sizeof(
struct CallbackEntry) * MAX_CALLBACKS);
274 mythread.attr = TH_C;
275 mythread.option = PWROFF_IRX;
276 mythread.thread = poweroff_rpc_Thread;
277 mythread.stacksize = 0x1000;
278 mythread.priority = 0x27;
280 int pid = CreateThread(&mythread);
285 if ((i=StartThread(pid, NULL)) < 0) {
286 M_PRINTF(
"StartThread failed (%d)\n", i);
287 return MODULE_NO_RESIDENT_END;
291 M_PRINTF(
"CreateThread failed (%d)\n", pid);
292 return MODULE_NO_RESIDENT_END;
295 M_PRINTF(
"Poweroff installed\n");
296 return MODULE_RESIDENT_END;