continue with pandora port
[fceu.git] / drivers / pandora / pandora.c
CommitLineData
b054fd77 1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <sys/ioctl.h>
8#include <unistd.h>
9#include <linux/input.h>
10#include <linux/omapfb.h>
11
12#include "../common/platform.h"
13#include "../common/input.h"
14#include "../common/settings.h"
15#include "../common/main.h"
16#include "../common/args.h"
17#include "../../video.h"
18#include "../arm/asmutils.h"
19#include "../libpicofe/input.h"
20#include "../libpicofe/plat.h"
21#include "../libpicofe/menu.h"
22#include "../libpicofe/linux/in_evdev.h"
23#include "../libpicofe/linux/fbdev.h"
24#include "../libpicofe/linux/xenv.h"
25
26static int g_layer_x, g_layer_y, g_layer_w, g_layer_h;
27static struct vout_fbdev *main_fb, *layer_fb;
28static void *layer_buf;
29static int bounce_buf[320 * 241 / 4];
30static unsigned short pal[256];
31
44343b87 32enum scaling {
33 SCALING_1X,
34 SCALING_PROPORTIONAL,
35 SCALING_4_3,
36 SCALING_FULLSCREEN,
37};
38
b054fd77 39static const struct in_default_bind in_evdev_defbinds[] = {
40 { KEY_UP, IN_BINDTYPE_PLAYER12, NKEYB_UP },
41 { KEY_DOWN, IN_BINDTYPE_PLAYER12, NKEYB_DOWN },
42 { KEY_LEFT, IN_BINDTYPE_PLAYER12, NKEYB_LEFT },
43 { KEY_RIGHT, IN_BINDTYPE_PLAYER12, NKEYB_RIGHT },
44 { KEY_PAGEDOWN, IN_BINDTYPE_PLAYER12, NKEYB_B },
45 { KEY_END, IN_BINDTYPE_PLAYER12, NKEYB_A },
46 { KEY_HOME, IN_BINDTYPE_PLAYER12, NKEYB_B_TURBO },
47 { KEY_PAGEUP, IN_BINDTYPE_PLAYER12, NKEYB_A_TURBO },
48 { KEY_LEFTCTRL, IN_BINDTYPE_PLAYER12, NKEYB_SELECT },
49 { KEY_LEFTALT, IN_BINDTYPE_PLAYER12, NKEYB_START },
44343b87 50 { KEY_1, IN_BINDTYPE_EMU, EACTB_SAVE_STATE },
51 { KEY_2, IN_BINDTYPE_EMU, EACTB_LOAD_STATE },
52 { KEY_3, IN_BINDTYPE_EMU, EACTB_PREV_SLOT },
53 { KEY_4, IN_BINDTYPE_EMU, EACTB_NEXT_SLOT },
54 { KEY_5, IN_BINDTYPE_EMU, EACTB_FDS_INSERT },
55 { KEY_6, IN_BINDTYPE_EMU, EACTB_FDS_SELECT },
56 { KEY_7, IN_BINDTYPE_EMU, EACTB_INSERT_COIN },
b054fd77 57 { KEY_SPACE, IN_BINDTYPE_EMU, EACTB_ENTER_MENU },
58 { 0, 0, 0 }
59};
60
61static int omap_setup_layer_(int fd, int enabled, int x, int y, int w, int h)
62{
63 struct omapfb_plane_info pi = { 0, };
64 struct omapfb_mem_info mi = { 0, };
65 int ret;
66
67 ret = ioctl(fd, OMAPFB_QUERY_PLANE, &pi);
68 if (ret != 0) {
69 perror("QUERY_PLANE");
70 return -1;
71 }
72
73 ret = ioctl(fd, OMAPFB_QUERY_MEM, &mi);
74 if (ret != 0) {
75 perror("QUERY_MEM");
76 return -1;
77 }
78
79 /* must disable when changing stuff */
80 if (pi.enabled) {
81 pi.enabled = 0;
82 ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
83 if (ret != 0)
84 perror("SETUP_PLANE");
85 }
86
87 if (mi.size < 640*512*3*3) {
88 mi.size = 640*512*3*3;
89 ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi);
90 if (ret != 0) {
91 perror("SETUP_MEM");
92 return -1;
93 }
94 }
95
96 pi.pos_x = x;
97 pi.pos_y = y;
98 pi.out_width = w;
99 pi.out_height = h;
100 pi.enabled = enabled;
101
102 ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
103 if (ret != 0) {
104 perror("SETUP_PLANE");
105 return -1;
106 }
107
108 return 0;
109}
110
111static int omap_enable_layer(int enabled)
112{
113 return omap_setup_layer_(vout_fbdev_get_fd(layer_fb), enabled,
114 g_layer_x, g_layer_y, g_layer_w, g_layer_h);
115}
116
117void platform_init(void)
118{
119 const char *main_fb_name, *layer_fb_name;
120 int fd, ret, w, h;
121
122 memset(&Settings, 0, sizeof(Settings));
123 Settings.frameskip = 0;
124 Settings.sound_rate = 44100;
125 Settings.turbo_rate_add = (8*2 << 24) / 60 + 1; // 8Hz turbofire
126 Settings.gamma = 100;
127 Settings.sstate_confirm = 1;
44343b87 128 Settings.scaling = SCALING_4_3;
b054fd77 129
130 main_fb_name = getenv("FBDEV_MAIN");
131 if (main_fb_name == NULL)
132 main_fb_name = "/dev/fb0";
133
134 layer_fb_name = getenv("FBDEV_LAYER");
135 if (layer_fb_name == NULL)
136 layer_fb_name = "/dev/fb1";
137
138 // must set the layer up first to be able to use it
139 fd = open(layer_fb_name, O_RDWR);
140 if (fd == -1) {
141 fprintf(stderr, "%s: ", layer_fb_name);
142 perror("open");
143 exit(1);
144 }
145
146 g_layer_x = 80, g_layer_y = 0;
147 g_layer_w = 640, g_layer_h = 480;
148
149 ret = omap_setup_layer_(fd, 0, g_layer_x, g_layer_y, g_layer_w, g_layer_h);
150 close(fd);
151 if (ret != 0) {
152 fprintf(stderr, "failed to set up layer, exiting.\n");
153 exit(1);
154 }
155
156 xenv_init(NULL, "fceu");
157
158 w = h = 0;
159 main_fb = vout_fbdev_init(main_fb_name, &w, &h, 16, 2);
160 if (main_fb == NULL) {
161 fprintf(stderr, "couldn't init fb: %s\n", main_fb_name);
162 exit(1);
163 }
164
165 g_menuscreen_w = w;
166 g_menuscreen_h = h;
167 g_menuscreen_ptr = vout_fbdev_flip(main_fb);
168
169 w = 640;
170 h = 512;
171 layer_fb = vout_fbdev_init(layer_fb_name, &w, &h, 16, 3);
172 if (layer_fb == NULL) {
173 fprintf(stderr, "couldn't init fb: %s\n", layer_fb_name);
174 goto fail0;
175 }
176 layer_buf = vout_fbdev_resize(layer_fb, 256, 240, 16,
177 0, 0, 0, 0, 3);
178 if (layer_buf == NULL) {
179 fprintf(stderr, "couldn't get layer buf\n");
180 goto fail1;
181 }
182
183 plat_target_init();
b054fd77 184
185 XBuf = (void *)bounce_buf;
186
187 return;
188
189fail1:
190 vout_fbdev_finish(layer_fb);
191fail0:
192 vout_fbdev_finish(main_fb);
193 xenv_finish();
194 exit(1);
195}
196
197void platform_late_init(void)
198{
199 in_evdev_init(in_evdev_defbinds);
200 in_probe();
201 plat_target_setup_input();
202}
203
204/* video */
205void CleanSurface(void)
206{
207 memset(bounce_buf, 0, sizeof(bounce_buf));
208 vout_fbdev_clear(layer_fb);
209}
210
211void KillVideo(void)
212{
213}
214
215int InitVideo(void)
216{
217 CleanSurface();
218
219 srendline = 0;
220 erendline = 239;
221
222 return 1;
223}
224
225// 16: rrrr rggg gg0b bbbb
226void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b)
227{
228 pal[index] = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3);
229}
230
231void FCEUD_GetPalette(uint8 index, uint8 *r, uint8 *g, uint8 *b)
232{
233 unsigned int v = pal[index];
234 *r = (v >> 8) & 0xf8;
235 *g = (v >> 3) & 0xfc;
236 *b = v << 3;
237}
238
239void BlitPrepare(int skip)
240{
44343b87 241 char *s;
242 short *d;
243 int *p, i;
244
b054fd77 245 if (skip)
246 return;
247
248 if (eoptions & EO_CLIPSIDES)
249 {
250 int i, *p = bounce_buf + 32/4;
251 for (i = 240; i; i--, p += 320/4)
252 {
253 p[0] = p[1] = p[62] = p[63] = 0;
254 }
255 }
256
44343b87 257 p = bounce_buf + 32/4;
258 if (srendline > 0)
259 for (i = srendline; i > 0; i--, p += 320/4)
260 memset(p, 0, 256);
261 if (erendline < 239)
b054fd77 262 {
44343b87 263 p = bounce_buf + erendline*320/4 + 32/4;
264 for (i = 239-erendline; i > 0; i--, p += 320/4)
265 memset(p, 0, 256);
b054fd77 266 }
b054fd77 267
44343b87 268 /* this is called before throttle, so we blit here too */
269 s = (char *)bounce_buf + 32;
270 d = (short *)layer_buf;
b054fd77 271
272 for (i = 0; i < 239; i++, d += 256, s += 320)
273 do_clut(d, s, pal, 256);
274
275 layer_buf = vout_fbdev_flip(layer_fb);
276}
277
44343b87 278void BlitScreen(int skip)
279{
280}
281
282/* throttle */
283extern uint8 PAL;
284extern int FSkip;
285static struct timeval tv_expect;
286static int skip_count = 0;
287static int us_interval, us_interval1024;
288#define MAX_LAG_FRAMES 3
289
290void RefreshThrottleFPS(void)
291{
292 skip_count = 0;
293 us_interval = PAL ? 20000 : 16667;
294 us_interval1024 = PAL ? 20000*1024 : 17066667;
295
296 vout_fbdev_wait_vsync(layer_fb);
297 gettimeofday(&tv_expect, 0);
298 tv_expect.tv_usec *= 1024;
299}
300
301void SpeedThrottle(void)
302{
303 struct timeval now;
304 int diff;
305
306 gettimeofday(&now, 0);
307
308 // usec*1024 units to prevent drifting
309 tv_expect.tv_usec += us_interval1024;
310 if (tv_expect.tv_usec > 1000000 * 1024) {
311 tv_expect.tv_usec -= 1000000 * 1024;
312 tv_expect.tv_sec++;
313 }
314
315 diff = (tv_expect.tv_sec - now.tv_sec) * 1000000 +
316 (tv_expect.tv_usec >> 10) - now.tv_usec;
317
318 if (Settings.frameskip >= 0)
319 {
320 if (skip_count >= Settings.frameskip)
321 skip_count = 0;
322 else {
323 skip_count++;
324 FSkip = 1;
325 }
326 }
327 else
328 {
329 FSkip = diff < -us_interval;
330 }
331
332 if (diff > MAX_LAG_FRAMES * us_interval
333 || diff < -MAX_LAG_FRAMES * us_interval)
334 {
335 //printf("reset %d\n", diff);
336 RefreshThrottleFPS();
337 return;
338 }
339 else if (diff > us_interval)
340 {
341 usleep(diff - us_interval);
342 }
343}
344
345/* called just before emulation */
b054fd77 346void platform_apply_config(void)
347{
44343b87 348 float mult;
349
350 switch (Settings.scaling)
351 {
352 case SCALING_1X:
353 g_layer_w = 256;
354 g_layer_h = 240;
355 break;
356 case SCALING_PROPORTIONAL:
357 // assumes screen width > height
358 mult = (float)g_menuscreen_h / 240;
359 g_layer_w = (int)(256 * mult);
360 g_layer_h = g_menuscreen_h;
361 break;
362 case SCALING_4_3:
363 g_layer_w = g_menuscreen_h * 4 / 3;
364 g_layer_h = g_menuscreen_h;
365 break;
366 case SCALING_FULLSCREEN:
367 g_layer_w = g_menuscreen_w;
368 g_layer_h = g_menuscreen_h;
369 break;
370 }
371 if (g_layer_w > g_menuscreen_w)
372 g_layer_w = g_menuscreen_w;
373 if (g_layer_h > g_menuscreen_h)
374 g_layer_h = g_menuscreen_h;
375 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
376 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
377
378 plat_target_set_filter(Settings.hw_filter);
379 plat_target_set_lcdrate(PAL);
380
381 // adjust since we run at 60Hz, and real NES doesn't
382 FCEUI_Sound(Settings.sound_rate + Settings.sound_rate / 980);
383
384 omap_enable_layer(1);
b054fd77 385}
386
387void platform_set_volume(int val)
388{
389}
390
391void plat_video_menu_enter(int is_rom_loaded)
392{
44343b87 393 unsigned short *d = g_menubg_src_ptr;
394 unsigned char *s, *sr = (void *)bounce_buf;
395 int u, v = 240 / 2;
396 int x, y, w;
397
b054fd77 398 omap_enable_layer(0);
44343b87 399
400 if (!fceugi)
401 return;
402
403 for (y = 0; y < g_menuscreen_h; y++)
404 {
405 s = sr + v * 320 + 32;
406 u = 256 / 2;
407 for (x = 0; x < g_menuscreen_w; )
408 {
409 w = g_menuscreen_w - x;
410 if (w > 256 - u)
411 w = 256 - u;
412 do_clut(d + x, s + u, pal, w);
413 u = (u + w) & 255;
414 x += w;
415 }
416 d += x;
417 v++;
418 if (v > erendlinev[PAL])
419 v = srendlinev[PAL];
420 }
b054fd77 421}
422
423void plat_video_menu_begin(void)
424{
425}
426
427void plat_video_menu_end(void)
428{
429 g_menuscreen_ptr = vout_fbdev_flip(main_fb);
430}
431
432void plat_video_menu_leave(void)
433{
434 memset(g_menuscreen_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2);
435 g_menuscreen_ptr = vout_fbdev_flip(main_fb);
44343b87 436 // layer enabled in platform_apply_config()
b054fd77 437}
438
439char *DriverUsage="";
440
441ARGPSTRUCT DriverArgs[]={
442 {0,0,0,0}
443};
444
445void DoDriverArgs(void)
446{
447}
448
449void GetBaseDirectory(char *BaseDirectory)
450{
451 strcpy(BaseDirectory, "fceultra");
452}
453
454void platform_finish(void)
455{
456 omap_enable_layer(0);
457 vout_fbdev_finish(layer_fb);
458 vout_fbdev_finish(main_fb);
459 xenv_finish();
460}