/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Gameboy emulator based on gnuboy * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "plugin.h" #include "loader.h" #include "rockmacros.h" #include "input.h" #include "emu.h" #include "hw.h" #include "pcm.h" PLUGIN_HEADER PLUGIN_IRAM_DECLARE /* here is a global api struct pointer. while not strictly necessary, it's nice not to have to pass the api pointer in all function calls in the plugin */ struct plugin_api* rb; 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; } /* Using #define isn't enough with GCC 4.0.1 */ void* memcpy(void* dst, const void* src, size_t size) { return rb->memcpy(dst, src, size); } 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); if(fd < 0) /* no options to read, set defaults */ { options.LEFT=BUTTON_LEFT; options.RIGHT=BUTTON_RIGHT; #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 == RECORDER_PAD options.UP=BUTTON_UP; options.DOWN=BUTTON_DOWN; options.A=BUTTON_F1; options.B=BUTTON_F2; options.START=BUTTON_F3; options.SELECT=BUTTON_PLAY; 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 == IRIVER_IFP7XX_PAD options.UP=BUTTON_UP; options.DOWN=BUTTON_DOWN; options.A=BUTTON_PLAY; options.B=BUTTON_EQ; options.START=BUTTON_MODE; options.SELECT=(BUTTON_SELECT | BUTTON_REL); 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_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 == 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.UP=BUTTON_RC_PLAY; options.DOWN=BUTTON_RC_DOWN; options.LEFT=BUTTON_RC_REW; options.RIGHT=BUTTON_RC_FF; options.A=BUTTON_RC_VOL_DOWN; options.B=BUTTON_RC_VOL_UP; options.START=BUTTON_RC_HEART; options.SELECT=BUTTON_RC_MODE; options.MENU=BUTTON_POWER; #elif CONFIG_KEYPAD == COWOND2_PAD options.UP=BUTTON_UP; options.DOWN=BUTTON_DOWN; options.A=BUTTON_LEFT; options.B=BUTTON_RIGHT; options.START=BUTTON_PLUS; options.SELECT=BUTTON_SELECT; options.MENU=BUTTON_MENU; #else #error No Keymap Defined! #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); 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(char *rom) { rb->lcd_puts(0,0,"Init video"); vid_init(); rb->lcd_puts(0,1,"Init sound"); 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(); emu_run(); /* never reached */ return PLUGIN_OK; } /* this is the plugin entry point */ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { PLUGIN_IRAM_INIT(api) /* if you are using a global api pointer, don't forget to copy it! otherwise you will get lovely "I04: IllInstr" errors... :-) */ rb = api; rb->lcd_setfont(0); 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 MEM <= 8 && !defined(SIMULATOR) /* 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 gnuboy_main(parameter); #ifdef HAVE_WHEEL_POSITION rb->wheel_send_events(true); #endif if(shut&&!cleanshut) { rb->splash(HZ/2, errormsg); return PLUGIN_ERROR; } if(!rb->audio_status()) pcm_close(); rb->splash(HZ/2, "Closing Rockboy"); savesettings(); cleanup(); return PLUGIN_OK; }