add a hack for Decap Attack
[picodrive.git] / platform / psp / psp.c
CommitLineData
cff531af 1/*
2 * PicoDrive
3 * (C) notaz, 2007,2008
4 *
5 * This work is licensed under the terms of MAME license.
6 * See COPYING file in the top-level directory.
7 */
7d4906bf 8#include <stdio.h>
110df09c 9#include <stdlib.h>
7d4906bf 10#include <stdarg.h>
11#include <string.h>
ea08c296 12#include <unistd.h>
7d4906bf 13
1820b5a7 14#include <pspkernel.h>
7d4906bf 15#include <pspiofilemgr.h>
1820b5a7 16#include <pspdisplay.h>
70357ce5 17#include <psppower.h>
9caf44b5 18#include <psprtc.h>
1820b5a7 19#include <pspgu.h>
2445b7cb 20#include <pspsdk.h>
1820b5a7 21
22#include "psp.h"
b542be46 23#include "emu.h"
1820b5a7 24#include "../common/lprintf.h"
052c0f86 25#include "version.h"
1820b5a7 26
2445b7cb 27extern int pico_main(void);
28
29#ifndef FW15
30
2b02d6e5 31PSP_MODULE_INFO("PicoDrive", 0, 1, 51);
110df09c 32PSP_HEAP_SIZE_MAX();
1820b5a7 33
2445b7cb 34int main() { return pico_main(); } /* just a wrapper */
35
36#else
37
2b02d6e5 38PSP_MODULE_INFO("PicoDrive", 0x1000, 1, 51);
2445b7cb 39PSP_MAIN_THREAD_ATTR(0);
40
41int main()
42{
43 SceUID thid;
44
45 /* this is the thing we need the kernel mode for */
46 pspSdkInstallNoDeviceCheckPatch();
47
48 thid = sceKernelCreateThread("pico_main", (SceKernelThreadEntry) pico_main, 32, 0x2000, PSP_THREAD_ATTR_USER, NULL);
49 if (thid >= 0)
50 sceKernelStartThread(thid, 0, 0);
ff6b7429 51#ifndef GCOV
2445b7cb 52 sceKernelExitDeleteThread(0);
ff6b7429 53#else
54 while (engineState != PGS_Quit)
55 sceKernelDelayThread(1024 * 1024);
56#endif
2445b7cb 57
58 return 0;
59}
60
61#endif
62
2b02d6e5 63int psp_unhandled_suspend = 0;
64
9112b6ce 65unsigned int __attribute__((aligned(16))) guCmdList[GU_CMDLIST_SIZE];
66
67void *psp_screen = VRAM_FB0;
ea08c296 68
1820b5a7 69static int current_screen = 0; /* front bufer */
70
110df09c 71static SceUID main_thread_id = -1;
72
9caf44b5 73#define ANALOG_DEADZONE 80
1820b5a7 74
75/* Exit callback */
76static int exit_callback(int arg1, int arg2, void *common)
77{
78 sceKernelExitGame();
79 return 0;
80}
81
b542be46 82/* Power Callback */
83static int power_callback(int unknown, int pwrflags, void *common)
84{
7d0143a2 85 lprintf("power_callback: flags: 0x%08X\n", pwrflags);
86
b542be46 87 /* check for power switch and suspending as one is manual and the other automatic */
7d0143a2 88 if (pwrflags & PSP_POWER_CB_POWER_SWITCH || pwrflags & PSP_POWER_CB_SUSPENDING || pwrflags & PSP_POWER_CB_STANDBY)
b542be46 89 {
2b02d6e5 90 psp_unhandled_suspend = 1;
91 if (engineState != PGS_Suspending)
92 engineStateSuspend = engineState;
93 sceKernelDelayThread(100000); // ??
b542be46 94 }
7d0143a2 95 else if (pwrflags & PSP_POWER_CB_RESUME_COMPLETE)
ea08c296 96 {
2b02d6e5 97 engineState = PGS_SuspendWake;
ea08c296 98 }
7d0143a2 99
2445b7cb 100 //sceDisplayWaitVblankStart();
b542be46 101 return 0;
102}
103
1820b5a7 104/* Callback thread */
105static int callback_thread(SceSize args, void *argp)
106{
107 int cbid;
108
4b167c12 109 lprintf("callback_thread started with id %08x, priority %i\n",
a4221917 110 sceKernelGetThreadId(), sceKernelGetThreadCurrentPriority());
1820b5a7 111
112 cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
113 sceKernelRegisterExitCallback(cbid);
b542be46 114 cbid = sceKernelCreateCallback("Power Callback", power_callback, NULL);
115 scePowerRegisterCallback(0, cbid);
1820b5a7 116
117 sceKernelSleepThreadCB();
118
119 return 0;
120}
121
122void psp_init(void)
123{
a4221917 124 SceUID thid;
ea08c296 125 char buff[128], *r;
126
127 /* fw 1.5 sometimes returns 8002032c, although getcwd works */
128 r = getcwd(buff, sizeof(buff));
129 if (r) sceIoChdir(buff);
1820b5a7 130
110df09c 131 main_thread_id = sceKernelGetThreadId();
132
052c0f86 133 lprintf("\n%s\n", "PicoDrive v" VERSION " " __DATE__ " " __TIME__);
110df09c 134 lprintf("running on %08x kernel\n", sceKernelDevkitVersion()),
135 lprintf("entered psp_init, threadId %08x, priority %i\n", main_thread_id,
a4221917 136 sceKernelGetThreadCurrentPriority());
1820b5a7 137
2445b7cb 138 thid = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, NULL);
1820b5a7 139 if (thid >= 0)
140 {
141 sceKernelStartThread(thid, 0, 0);
142 }
143
144 /* video */
145 sceDisplaySetMode(0, 480, 272);
9112b6ce 146 sceDisplaySetFrameBuf(VRAM_FB1, 512, PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
1820b5a7 147 current_screen = 1;
9112b6ce 148 psp_screen = VRAM_FB0;
1820b5a7 149
150 /* gu */
151 sceGuInit();
152
9112b6ce 153 sceGuStart(GU_DIRECT, guCmdList);
8ab3e3c1 154 sceGuDrawBuffer(GU_PSM_5650, (void *)VRAMOFFS_FB0, 512);
155 sceGuDispBuffer(480, 272, (void *)VRAMOFFS_FB1, 512); // don't care
9112b6ce 156 sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT);
8ab3e3c1 157 sceGuDepthBuffer((void *)VRAMOFFS_DEPTH, 512);
9112b6ce 158 sceGuOffset(2048 - (480 / 2), 2048 - (272 / 2));
159 sceGuViewport(2048, 2048, 480, 272);
160 sceGuDepthRange(0xc350, 0x2710);
161 sceGuScissor(0, 0, 480, 272);
162 sceGuEnable(GU_SCISSOR_TEST);
9112b6ce 163
164 sceGuDepthMask(0xffff);
165 sceGuDisable(GU_DEPTH_TEST);
166
167 sceGuFrontFace(GU_CW);
9112b6ce 168 sceGuEnable(GU_TEXTURE_2D);
9112b6ce 169 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
8ab3e3c1 170 sceGuAmbientColor(0xffffffff);
171 sceGuColor(0xffffffff);
9112b6ce 172 sceGuFinish();
173 sceGuSync(0, 0);
174
175 sceDisplayWaitVblankStart();
176 sceGuDisplay(GU_TRUE);
177
178
1820b5a7 179 /* input */
180 sceCtrlSetSamplingCycle(0);
9caf44b5 181 sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
1820b5a7 182}
183
184void psp_finish(void)
185{
aefb65bc 186 lprintf("psp_finish..\n");
1820b5a7 187 sceGuTerm();
188
189 //sceKernelSleepThread();
190 sceKernelExitGame();
191}
192
7d4906bf 193void psp_video_flip(int wait_vsync)
1820b5a7 194{
7d4906bf 195 if (wait_vsync) sceDisplayWaitVblankStart();
70357ce5 196 sceDisplaySetFrameBuf(psp_screen, 512, PSP_DISPLAY_PIXEL_FORMAT_565,
197 wait_vsync ? PSP_DISPLAY_SETBUF_IMMEDIATE : PSP_DISPLAY_SETBUF_NEXTFRAME);
1820b5a7 198 current_screen ^= 1;
9112b6ce 199 psp_screen = current_screen ? VRAM_FB0 : VRAM_FB1;
7d4906bf 200}
201
202void *psp_video_get_active_fb(void)
203{
9112b6ce 204 return current_screen ? VRAM_FB1 : VRAM_FB0;
1820b5a7 205}
206
207void psp_video_switch_to_single(void)
208{
9112b6ce 209 psp_screen = VRAM_FB0;
1820b5a7 210 sceDisplaySetFrameBuf(psp_screen, 512, PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
211 current_screen = 0;
212}
213
214void psp_msleep(int ms)
215{
216 sceKernelDelayThread(ms * 1000);
217}
218
7d4906bf 219unsigned int psp_pad_read(int blocking)
1820b5a7 220{
9caf44b5 221 unsigned int buttons;
1820b5a7 222 SceCtrlData pad;
7d4906bf 223 if (blocking)
224 sceCtrlReadBufferPositive(&pad, 1);
225 else sceCtrlPeekBufferPositive(&pad, 1);
9caf44b5 226 buttons = pad.Buttons;
227
228 // analog..
e5ab6faf 229 buttons &= ~(PBTN_NUB_UP|PBTN_NUB_DOWN|PBTN_NUB_LEFT|PBTN_NUB_RIGHT);
230 if (pad.Lx < 128 - ANALOG_DEADZONE) buttons |= PBTN_NUB_LEFT;
231 if (pad.Lx > 128 + ANALOG_DEADZONE) buttons |= PBTN_NUB_RIGHT;
232 if (pad.Ly < 128 - ANALOG_DEADZONE) buttons |= PBTN_NUB_UP;
233 if (pad.Ly > 128 + ANALOG_DEADZONE) buttons |= PBTN_NUB_DOWN;
1820b5a7 234
9caf44b5 235 return buttons;
1820b5a7 236}
237
70357ce5 238int psp_get_cpu_clock(void)
239{
240 return scePowerGetCpuClockFrequencyInt();
241}
242
243int psp_set_cpu_clock(int clock)
244{
245 int ret = scePowerSetClockFrequency(clock, clock, clock/2);
246 if (ret != 0) lprintf("failed to set clock: %i\n", ret);
247
248 return ret;
249}
250
9caf44b5 251char *psp_get_status_line(void)
252{
253 static char buff[64];
254 int ret, bat_percent, bat_time;
255 pspTime time;
256
257 ret = sceRtcGetCurrentClockLocalTime(&time);
258 bat_percent = scePowerGetBatteryLifePercent();
259 bat_time = scePowerGetBatteryLifeTime();
260 if (ret < 0 || bat_percent < 0 || bat_time < 0) return NULL;
261
262 snprintf(buff, sizeof(buff), "%02i:%02i bat: %3i%%", time.hour, time.minutes, bat_percent);
263 if (!scePowerIsPowerOnline())
264 snprintf(buff+strlen(buff), sizeof(buff)-strlen(buff), " (%i:%02i)", bat_time/60, bat_time%60);
265 return buff;
266}
267
7d0143a2 268void psp_wait_suspend(void)
269{
270 // probably should do something smarter here?
271 sceDisplayWaitVblankStart();
272}
273
ea08c296 274void psp_resume_suspend(void)
275{
276 // for some reason file IO doesn't seem to work
277 // after resume for some period of time, at least on 1.5
278 SceUID fd;
279 int i;
280 for (i = 0; i < 30; i++) {
2b1f0e25 281 fd = sceIoOpen("EBOOT.PBP", PSP_O_RDONLY, 0777);
282 if (fd >= 0) break;
283 sceKernelDelayThread(100 * 1024);
ea08c296 284 }
285 if (fd >= 0) sceIoClose(fd);
286 sceDisplayWaitVblankStart();
ea08c296 287 if (i < 30)
2b1f0e25 288 lprintf("io resumed after %i tries\n", i);
289 else {
290 lprintf("io resume failed with %08x\n", fd);
291 sceKernelDelayThread(500 * 1024);
292 }
ea08c296 293}
294
7d4906bf 295/* alt logging */
110df09c 296#define LOG_FILE "log.txt"
297
c6196c0f 298#ifndef LPRINTF_STDIO
110df09c 299typedef struct _log_entry
300{
301 char buff[256];
302 struct _log_entry *next;
303} log_entry;
7d4906bf 304
110df09c 305static log_entry *le_root = NULL;
c6196c0f 306#endif
9caf44b5 307
052c0f86 308/* strange: if this function leaks memory (before psp_init() call?),
309 * resume after suspend breaks on 3.90 */
7d0143a2 310void lprintf(const char *fmt, ...)
7d4906bf 311{
312 va_list vl;
110df09c 313
314#ifdef LPRINTF_STDIO
315 va_start(vl, fmt);
316 vprintf(fmt, vl);
317 va_end(vl);
318#else
319 static SceUID logfd = -1;
ea08c296 320 static int msg_count = 0;
7d4906bf 321 char buff[256];
110df09c 322 log_entry *le, *le1;
7d4906bf 323
9caf44b5 324 if (logfd == -2) return; // disabled
325
110df09c 326 va_start(vl, fmt);
327 vsnprintf(buff, sizeof(buff), fmt, vl);
328 va_end(vl);
329
330 // note: this is still unsafe code
331 if (main_thread_id != sceKernelGetThreadId())
7d4906bf 332 {
110df09c 333 le = malloc(sizeof(*le));
334 if (le == NULL) return;
335 le->next = NULL;
336 strcpy(le->buff, buff);
337 if (le_root == NULL) le_root = le;
338 else {
339 for (le1 = le_root; le1->next != NULL; le1 = le1->next);
340 le1->next = le;
9caf44b5 341 }
110df09c 342 return;
7d4906bf 343 }
344
110df09c 345 logfd = sceIoOpen(LOG_FILE, PSP_O_WRONLY|PSP_O_APPEND, 0777);
346 if (logfd < 0) {
ea08c296 347 if (msg_count == 0) logfd = -2;
110df09c 348 return;
349 }
350
351 if (le_root != NULL)
352 {
353 le1 = le_root;
354 le_root = NULL;
355 sceKernelDelayThread(1000);
356 while (le1 != NULL) {
357 le = le1;
358 le1 = le->next;
359 sceIoWrite(logfd, le->buff, strlen(le->buff));
360 free(le);
ea08c296 361 msg_count++;
110df09c 362 }
363 }
7d4906bf 364
365 sceIoWrite(logfd, buff, strlen(buff));
ea08c296 366 msg_count++;
9caf44b5 367
368 // make sure it gets flushed
369 sceIoClose(logfd);
370 logfd = -1;
110df09c 371#endif
7d4906bf 372}
373
374