rockbox/apps/plugins/rockboy/rockboy.c

640 lines
18 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Gameboy emulator based on gnuboy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "lib/helper.h"
#include "loader.h"
#include "rockmacros.h"
#include "input.h"
#include "emu.h"
#include "hw.h"
#include "pcm.h"
int shut,cleanshut;
char *errormsg;
#define optionname "options"
void die(char *message, ...)
{
shut=1;
errormsg=message;
}
struct options options;
void *audio_bufferbase;
void *audio_bufferpointer;
size_t audio_buffer_free;
void *my_malloc(size_t size)
{
void *alloc;
if (size + 4 > audio_buffer_free)
return 0;
alloc = audio_bufferpointer;
audio_bufferpointer += size + 4;
audio_buffer_free -= size + 4;
return alloc;
}
static void setoptions (void)
{
int fd;
DIR* dir;
char optionsave[sizeof(savedir)+sizeof(optionname)];
dir=rb->opendir(savedir);
if(!dir)
rb->mkdir(savedir);
else
rb->closedir(dir);
snprintf(optionsave, sizeof(optionsave), "%s/%s", savedir, optionname);
fd = open(optionsave, O_RDONLY);
int optionssize = sizeof(options);
int filesize = 0;
if(fd >= 0)
filesize = rb->filesize(fd);
/* don't read the option file if the size
* is not as expected to avoid crash */
if(fd < 0 || filesize!=optionssize)
{
/* no options to read, set defaults */
#ifdef HAVE_TOUCHSCREEN
options.LEFT = BUTTON_MIDLEFT;
options.RIGHT = BUTTON_MIDRIGHT;
#elif defined(BUTTON_LEFT) && defined(BUTTON_RIGHT)
options.LEFT = BUTTON_LEFT;
options.RIGHT = BUTTON_RIGHT;
#else
#warning "LEFT/RIGHT not defined!"
#endif
#if CONFIG_KEYPAD == IRIVER_H100_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_ON;
options.B = BUTTON_OFF;
options.START = BUTTON_REC;
options.SELECT = BUTTON_SELECT;
options.MENU = BUTTON_MODE;
#elif CONFIG_KEYPAD == IRIVER_H300_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_REC;
options.B = BUTTON_MODE;
options.START = BUTTON_ON;
options.SELECT = BUTTON_SELECT;
options.MENU = BUTTON_OFF;
#elif CONFIG_KEYPAD == IPOD_4G_PAD
options.UP = BUTTON_MENU;
options.DOWN = BUTTON_PLAY;
options.A = BUTTON_NONE;
options.B = BUTTON_NONE;
options.START = BUTTON_SELECT;
options.SELECT = BUTTON_NONE;
options.MENU = (BUTTON_SELECT | BUTTON_REPEAT);
#elif CONFIG_KEYPAD == GIGABEAT_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.START = BUTTON_A;
options.SELECT = BUTTON_SELECT;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == SANSA_E200_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_SELECT;
options.B = BUTTON_REC;
options.START = BUTTON_SCROLL_BACK;
options.SELECT = BUTTON_SCROLL_FWD;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == SANSA_FUZE_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_SELECT;
options.B = BUTTON_HOME;
options.START = BUTTON_SCROLL_BACK;
options.SELECT = BUTTON_SCROLL_FWD;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == SANSA_C200_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_SELECT;
options.B = BUTTON_REC;
options.START = BUTTON_VOL_DOWN;
options.SELECT = BUTTON_VOL_UP;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == SANSA_CLIP_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_SELECT;
options.B = BUTTON_HOME;
options.START = BUTTON_VOL_DOWN;
options.SELECT = BUTTON_VOL_UP;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_PLAY;
options.B = BUTTON_REC;
options.START = BUTTON_SELECT;
options.SELECT = BUTTON_NONE;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == IRIVER_H10_PAD
options.UP = BUTTON_SCROLL_UP;
options.DOWN = BUTTON_SCROLL_DOWN;
options.A = BUTTON_PLAY;
options.B = BUTTON_FF;
options.START = BUTTON_REW;
options.SELECT = BUTTON_NONE;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == MROBE500_PAD
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == COWON_D2_PAD
options.A = BUTTON_PLUS;
options.B = BUTTON_MINUS;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == GIGABEAT_S_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.START = BUTTON_PLAY;
options.SELECT = BUTTON_SELECT;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_CUSTOM;
options.B = BUTTON_PLAY;
options.START = BUTTON_BACK;
options.SELECT = BUTTON_SELECT;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.START = BUTTON_PLAY;
options.SELECT = BUTTON_NONE;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.START = BUTTON_VIEW;
options.SELECT = BUTTON_SELECT;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.START = BUTTON_NEXT;
options.SELECT = BUTTON_PLAY;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.START = BUTTON_RIGHT;
options.SELECT = BUTTON_LEFT;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == ONDAVX747_PAD
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == ONDAVX777_PAD
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == SAMSUNG_YH92X_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_PLAY;
options.B = BUTTON_FFWD;
options.START = BUTTON_REW;
options.SELECT = BUTTON_NONE;
options.MENU = BUTTON_REC_SW_ON;
#elif CONFIG_KEYPAD == SAMSUNG_YH820_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.A = BUTTON_PLAY;
options.B = BUTTON_FFWD;
options.START = BUTTON_REW;
options.SELECT = BUTTON_NONE;
options.MENU = BUTTON_REC;
#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
options.UP = BUTTON_OK;
options.DOWN = BUTTON_CANCEL;
options.LEFT = BUTTON_PREV;
options.RIGHT = BUTTON_NEXT;
options.A = BUTTON_POWER;
options.B = BUTTON_REC;
options.START = BUTTON_PLAY;
options.SELECT = BUTTON_UP;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == MPIO_HD300_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.LEFT = BUTTON_REW;
options.RIGHT = BUTTON_FF;
options.A = BUTTON_PLAY;
options.B = BUTTON_REC;
options.START = (BUTTON_PLAY | BUTTON_REPEAT);
options.SELECT = BUTTON_ENTER;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.LEFT = BUTTON_LEFT;
options.RIGHT = BUTTON_RIGHT;
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.START = BUTTON_SELECT;
options.SELECT = BUTTON_PLAYPAUSE;
options.MENU = BUTTON_BACK;
#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.LEFT = BUTTON_LEFT;
options.RIGHT = BUTTON_RIGHT;
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.START = BUTTON_PREV;
options.SELECT = BUTTON_NEXT;
options.MENU = BUTTON_SELECT;
#elif CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.LEFT = BUTTON_LEFT;
options.RIGHT = BUTTON_RIGHT;
options.A = BUTTON_SELECT;
options.B = BUTTON_BACK;
options.START = BUTTON_POWER;
options.SELECT = BUTTON_USER;
options.MENU = BUTTON_MENU;
#elif CONFIG_KEYPAD == HM801_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.LEFT = BUTTON_LEFT;
options.RIGHT = BUTTON_RIGHT;
options.A = BUTTON_PREV;
options.B = BUTTON_NEXT;
options.START = BUTTON_PLAY;
options.SELECT = BUTTON_SELECT;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == SONY_NWZ_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.LEFT = BUTTON_LEFT;
options.RIGHT = BUTTON_RIGHT;
options.START = BUTTON_PLAY;
options.MENU = BUTTON_BACK;
options.SELECT = (BUTTON_POWER|BUTTON_PLAY);
options.A = (BUTTON_POWER|BUTTON_LEFT);
options.B = (BUTTON_POWER|BUTTON_RIGHT);
#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.LEFT = BUTTON_LEFT;
options.RIGHT = BUTTON_RIGHT;
options.START = BUTTON_BACK;
options.MENU = BUTTON_MENU;
options.SELECT = BUTTON_SELECT;
options.A = BUTTON_SHORTCUT;
options.B = BUTTON_PLAYPAUSE;
#elif CONFIG_KEYPAD == DX50_PAD
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.MENU = BUTTON_POWER;
options.START = BUTTON_LEFT;
options.SELECT = BUTTON_RIGHT;
#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.LEFT = BUTTON_LEFT;
options.RIGHT = BUTTON_RIGHT;
options.START = BUTTON_SELECT;
options.MENU = BUTTON_POWER;
options.SELECT = BUTTON_SELECT|BUTTON_REPEAT;
options.A = BUTTON_VOLDOWN;
options.B = BUTTON_VOLUP;
#elif CONFIG_KEYPAD == XDUOO_X3_PAD
options.UP = BUTTON_PREV;
options.DOWN = BUTTON_NEXT;
options.A = BUTTON_HOME;
options.B = BUTTON_OPTION;
options.START = BUTTON_VOL_DOWN;
options.SELECT = BUTTON_VOL_UP;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD
options.UP = BUTTON_PREV;
options.DOWN = BUTTON_NEXT;
options.A = BUTTON_HOME;
options.B = BUTTON_OPTION;
options.START = BUTTON_VOL_DOWN;
options.SELECT = BUTTON_VOL_UP;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD
options.UP = BUTTON_PREV;
options.DOWN = BUTTON_NEXT;
options.A = BUTTON_HOME;
options.B = BUTTON_OPTION;
options.START = BUTTON_VOL_DOWN;
options.SELECT = BUTTON_VOL_UP;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD
options.UP = BUTTON_PREV;
options.DOWN = BUTTON_NEXT;
options.A = BUTTON_VOL_UP;
options.B = BUTTON_VOL_DOWN;
options.START = BUTTON_PLAY;
options.SELECT = BUTTON_HOME;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == EROSQ_PAD
options.UP = BUTTON_PREV;
options.DOWN = BUTTON_NEXT;
options.LEFT = BUTTON_SCROLL_BACK;
options.RIGHT = BUTTON_SCROLL_FWD;
options.A = BUTTON_MENU;
options.B = BUTTON_BACK;
options.START = BUTTON_VOL_DOWN;
options.SELECT = BUTTON_VOL_UP;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
options.UP = BUTTON_UP;
options.DOWN = BUTTON_DOWN;
options.LEFT = BUTTON_LEFT;
options.RIGHT = BUTTON_RIGHT;
options.A = BUTTON_MENU;
options.B = BUTTON_BACK;
options.START = BUTTON_VOL_DOWN;
options.SELECT = BUTTON_VOL_UP;
options.MENU = BUTTON_POWER;
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
/* use touchscreen */
#else
#error No Keymap Defined!
#endif
#ifdef HAVE_TOUCHSCREEN
options.UP = BUTTON_TOPMIDDLE;
options.DOWN = BUTTON_BOTTOMMIDDLE;
options.START = BUTTON_TOPRIGHT;
options.SELECT = BUTTON_CENTER;
#if CONFIG_KEYPAD == MROBE500_PAD
options.A = BUTTON_BOTTOMLEFT;
options.B = BUTTON_BOTTOMRIGHT;
#elif (CONFIG_KEYPAD != COWON_D2_PAD ) || (CONFIG_KEYPAD != DX50_PAD )
options.A = BUTTON_BOTTOMLEFT;
options.B = BUTTON_BOTTOMRIGHT;
options.MENU = BUTTON_TOPLEFT;
#endif
#endif
options.maxskip=4;
options.fps=0;
options.showstats=0;
#if (LCD_WIDTH>=160) && (LCD_HEIGHT>=144)
options.scaling=0;
#else
options.scaling=1;
#endif
options.sound=1;
options.pal=0;
}
else
read(fd,&options, sizeof(options));
close(fd);
}
static void savesettings(void)
{
int fd;
char optionsave[sizeof(savedir)+sizeof(optionname)];
if(options.dirty)
{
options.dirty=0;
snprintf(optionsave, sizeof(optionsave), "%s/%s", savedir, optionname);
fd = open(optionsave, O_WRONLY|O_CREAT|O_TRUNC, 0666);
write(fd,&options, sizeof(options));
close(fd);
}
}
void doevents(void)
{
event_t ev;
int st;
ev_poll();
while (ev_getevent(&ev))
{
if (ev.type != EV_PRESS && ev.type != EV_RELEASE)
continue;
st = (ev.type != EV_RELEASE);
pad_set(ev.code, st);
}
}
static int gnuboy_main(const char *rom)
{
rb->lcd_puts(0,0,"Init video");
vid_init();
rb->lcd_puts(0,1,"Init sound");
rockboy_pcm_init();
rb->lcd_puts(0,2,"Loading rom");
loader_init(rom);
if(shut)
return PLUGIN_ERROR;
rb->lcd_puts(0,3,"Emu reset");
emu_reset();
rb->lcd_puts(0,4,"Emu run");
rb->lcd_clear_display();
rb->lcd_update();
if(options.autosave) sn_load();
emu_run();
/* never reached */
return PLUGIN_OK;
}
/* this is the plugin entry point */
enum plugin_status plugin_start(const void* parameter)
{
rb->lcd_setfont(FONT_SYSFIXED);
rb->lcd_clear_display();
if (!parameter)
{
rb->splash(HZ*3, "Play gameboy ROM file! (.gb/.gbc)");
return PLUGIN_OK;
}
if(rb->audio_status())
{
audio_bufferbase = audio_bufferpointer
= rb->plugin_get_buffer(&audio_buffer_free);
plugbuf=true;
}
else
{
audio_bufferbase = audio_bufferpointer
= rb->plugin_get_audio_buffer(&audio_buffer_free);
plugbuf=false;
}
#if MEMORYSIZE <= 8 && (CONFIG_PLATFORM & PLATFORM_NATIVE)
/* loaded as an overlay plugin, protect from overwriting ourselves */
if ((unsigned)(plugin_start_addr - (unsigned char *)audio_bufferbase)
< audio_buffer_free)
audio_buffer_free = plugin_start_addr - (unsigned char *)audio_bufferbase;
#endif
setoptions();
shut=0;
cleanshut=0;
#ifdef HAVE_WHEEL_POSITION
rb->wheel_send_events(false);
#endif
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
rb->lcd_set_mode(LCD_MODE_PAL256);
#endif
#ifdef HAVE_BACKLIGHT
/* ignore backlight time out */
backlight_ignore_timeout();
#endif
gnuboy_main(parameter);
#ifdef HAVE_WHEEL_POSITION
rb->wheel_send_events(true);
#endif
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
rb->lcd_set_mode(LCD_MODE_RGB565);
#endif
#ifdef HAVE_BACKLIGHT
backlight_use_settings();
#endif
if(!rb->audio_status())
rockboy_pcm_close();
if(shut&&!cleanshut)
{
rb->splash(HZ/2, errormsg);
return PLUGIN_ERROR;
}
rb->splash(HZ/2, "Closing Rockboy");
savesettings();
cleanup();
return PLUGIN_OK;
}