add a hack for Decap Attack
[picodrive.git] / platform / psp / psp.c
... / ...
CommitLineData
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 */
8#include <stdio.h>
9#include <stdlib.h>
10#include <stdarg.h>
11#include <string.h>
12#include <unistd.h>
13
14#include <pspkernel.h>
15#include <pspiofilemgr.h>
16#include <pspdisplay.h>
17#include <psppower.h>
18#include <psprtc.h>
19#include <pspgu.h>
20#include <pspsdk.h>
21
22#include "psp.h"
23#include "emu.h"
24#include "../common/lprintf.h"
25#include "version.h"
26
27extern int pico_main(void);
28
29#ifndef FW15
30
31PSP_MODULE_INFO("PicoDrive", 0, 1, 51);
32PSP_HEAP_SIZE_MAX();
33
34int main() { return pico_main(); } /* just a wrapper */
35
36#else
37
38PSP_MODULE_INFO("PicoDrive", 0x1000, 1, 51);
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);
51#ifndef GCOV
52 sceKernelExitDeleteThread(0);
53#else
54 while (engineState != PGS_Quit)
55 sceKernelDelayThread(1024 * 1024);
56#endif
57
58 return 0;
59}
60
61#endif
62
63int psp_unhandled_suspend = 0;
64
65unsigned int __attribute__((aligned(16))) guCmdList[GU_CMDLIST_SIZE];
66
67void *psp_screen = VRAM_FB0;
68
69static int current_screen = 0; /* front bufer */
70
71static SceUID main_thread_id = -1;
72
73#define ANALOG_DEADZONE 80
74
75/* Exit callback */
76static int exit_callback(int arg1, int arg2, void *common)
77{
78 sceKernelExitGame();
79 return 0;
80}
81
82/* Power Callback */
83static int power_callback(int unknown, int pwrflags, void *common)
84{
85 lprintf("power_callback: flags: 0x%08X\n", pwrflags);
86
87 /* check for power switch and suspending as one is manual and the other automatic */
88 if (pwrflags & PSP_POWER_CB_POWER_SWITCH || pwrflags & PSP_POWER_CB_SUSPENDING || pwrflags & PSP_POWER_CB_STANDBY)
89 {
90 psp_unhandled_suspend = 1;
91 if (engineState != PGS_Suspending)
92 engineStateSuspend = engineState;
93 sceKernelDelayThread(100000); // ??
94 }
95 else if (pwrflags & PSP_POWER_CB_RESUME_COMPLETE)
96 {
97 engineState = PGS_SuspendWake;
98 }
99
100 //sceDisplayWaitVblankStart();
101 return 0;
102}
103
104/* Callback thread */
105static int callback_thread(SceSize args, void *argp)
106{
107 int cbid;
108
109 lprintf("callback_thread started with id %08x, priority %i\n",
110 sceKernelGetThreadId(), sceKernelGetThreadCurrentPriority());
111
112 cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
113 sceKernelRegisterExitCallback(cbid);
114 cbid = sceKernelCreateCallback("Power Callback", power_callback, NULL);
115 scePowerRegisterCallback(0, cbid);
116
117 sceKernelSleepThreadCB();
118
119 return 0;
120}
121
122void psp_init(void)
123{
124 SceUID thid;
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);
130
131 main_thread_id = sceKernelGetThreadId();
132
133 lprintf("\n%s\n", "PicoDrive v" VERSION " " __DATE__ " " __TIME__);
134 lprintf("running on %08x kernel\n", sceKernelDevkitVersion()),
135 lprintf("entered psp_init, threadId %08x, priority %i\n", main_thread_id,
136 sceKernelGetThreadCurrentPriority());
137
138 thid = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, NULL);
139 if (thid >= 0)
140 {
141 sceKernelStartThread(thid, 0, 0);
142 }
143
144 /* video */
145 sceDisplaySetMode(0, 480, 272);
146 sceDisplaySetFrameBuf(VRAM_FB1, 512, PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
147 current_screen = 1;
148 psp_screen = VRAM_FB0;
149
150 /* gu */
151 sceGuInit();
152
153 sceGuStart(GU_DIRECT, guCmdList);
154 sceGuDrawBuffer(GU_PSM_5650, (void *)VRAMOFFS_FB0, 512);
155 sceGuDispBuffer(480, 272, (void *)VRAMOFFS_FB1, 512); // don't care
156 sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT);
157 sceGuDepthBuffer((void *)VRAMOFFS_DEPTH, 512);
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);
163
164 sceGuDepthMask(0xffff);
165 sceGuDisable(GU_DEPTH_TEST);
166
167 sceGuFrontFace(GU_CW);
168 sceGuEnable(GU_TEXTURE_2D);
169 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
170 sceGuAmbientColor(0xffffffff);
171 sceGuColor(0xffffffff);
172 sceGuFinish();
173 sceGuSync(0, 0);
174
175 sceDisplayWaitVblankStart();
176 sceGuDisplay(GU_TRUE);
177
178
179 /* input */
180 sceCtrlSetSamplingCycle(0);
181 sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
182}
183
184void psp_finish(void)
185{
186 lprintf("psp_finish..\n");
187 sceGuTerm();
188
189 //sceKernelSleepThread();
190 sceKernelExitGame();
191}
192
193void psp_video_flip(int wait_vsync)
194{
195 if (wait_vsync) sceDisplayWaitVblankStart();
196 sceDisplaySetFrameBuf(psp_screen, 512, PSP_DISPLAY_PIXEL_FORMAT_565,
197 wait_vsync ? PSP_DISPLAY_SETBUF_IMMEDIATE : PSP_DISPLAY_SETBUF_NEXTFRAME);
198 current_screen ^= 1;
199 psp_screen = current_screen ? VRAM_FB0 : VRAM_FB1;
200}
201
202void *psp_video_get_active_fb(void)
203{
204 return current_screen ? VRAM_FB1 : VRAM_FB0;
205}
206
207void psp_video_switch_to_single(void)
208{
209 psp_screen = VRAM_FB0;
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
219unsigned int psp_pad_read(int blocking)
220{
221 unsigned int buttons;
222 SceCtrlData pad;
223 if (blocking)
224 sceCtrlReadBufferPositive(&pad, 1);
225 else sceCtrlPeekBufferPositive(&pad, 1);
226 buttons = pad.Buttons;
227
228 // analog..
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;
234
235 return buttons;
236}
237
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
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
268void psp_wait_suspend(void)
269{
270 // probably should do something smarter here?
271 sceDisplayWaitVblankStart();
272}
273
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++) {
281 fd = sceIoOpen("EBOOT.PBP", PSP_O_RDONLY, 0777);
282 if (fd >= 0) break;
283 sceKernelDelayThread(100 * 1024);
284 }
285 if (fd >= 0) sceIoClose(fd);
286 sceDisplayWaitVblankStart();
287 if (i < 30)
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 }
293}
294
295/* alt logging */
296#define LOG_FILE "log.txt"
297
298#ifndef LPRINTF_STDIO
299typedef struct _log_entry
300{
301 char buff[256];
302 struct _log_entry *next;
303} log_entry;
304
305static log_entry *le_root = NULL;
306#endif
307
308/* strange: if this function leaks memory (before psp_init() call?),
309 * resume after suspend breaks on 3.90 */
310void lprintf(const char *fmt, ...)
311{
312 va_list vl;
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;
320 static int msg_count = 0;
321 char buff[256];
322 log_entry *le, *le1;
323
324 if (logfd == -2) return; // disabled
325
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())
332 {
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;
341 }
342 return;
343 }
344
345 logfd = sceIoOpen(LOG_FILE, PSP_O_WRONLY|PSP_O_APPEND, 0777);
346 if (logfd < 0) {
347 if (msg_count == 0) logfd = -2;
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);
361 msg_count++;
362 }
363 }
364
365 sceIoWrite(logfd, buff, strlen(buff));
366 msg_count++;
367
368 // make sure it gets flushed
369 sceIoClose(logfd);
370 logfd = -1;
371#endif
372}
373
374