partially working menu
[fceu.git] / drivers / gp2x / minimal.c
index 0250587..ba4ffe0 100644 (file)
-/*
-  GP2X minimal library v0.A by rlyeh, 2005. emulnation.info@rlyeh (swap it!)
-
-  + GP2X 920t/940t CPUs library with a FIFO message system.
-  + GP2X video library with double buffering.
-  + GP2X sound library with double buffering.
-  + GP2X blitter library.
-  + GP2X timer library.
-  + GP2X joystick library.
-
-  Thanks to Squidge, Robster, snaff, Reesy and NK, for the help & previous work! :-)
-
-
-  License
-  =======
-
-  Free for non-commercial projects (it would be nice receiving a mail from you).
-  Other cases, ask me first.
-
-  GamePark Holdings is not allowed to use this library and/or use parts from it.
-
-
-  Known projects using the library or parts from it
-  =================================================
-
-  REminiscence-0.1.8 (rlyeh)
-  Atari800 GP2X pre-release 3 (foft)
-  XUMP (kedo)
-  MAME2X (Franxis)
-  DrMD for GP2X (Reesy)
-
-
-  What's new
-  ==========
-
-  0.A: 940t disabled all time unless required
-       sound is paused by default now, use gp2x_sound_pause() to unlock it
-
-       fixed functions:
-        - gp2x_sound_play()                        ; increased the number of sampling buffers
-        - gp2x_timer_read()                        ; it should work again. broken at some point before
-        - gp2x_dualcore_launch_program_from_disk() ; it missed the code uploading call
-
-       added functions:
-        - gp2x_sound_pause()
-        - gp2x_timer_delay()
-        - gp2x_dualcore_pause()
-
-  0.9: initial FIFO message system for dual cpu cores.
-       initial 48 Mb support.
-       initial quadruple buffering in 8bbp mode.
-
-       added functions:
-        - gp2x_dualcore_exec() ; initial FIFO message system for dual cpu cores.
-        - gp2x_dualcore_sync() ; initial FIFO message system for dual cpu cores.
-
-       improved functions:
-        - gp2x_video_flip()    ; initial quadruple buffering in 8bbp mode.
-
-  0.8: initial dual cores cpu support.
-       very basic blit functions by popular demand ;-)
-       vsync & hsync waiting code (thanks Reesy)
-
-       added functions:
-        - gp2x_launch_program()            ; initial dual cores cpu support.
-        - gp2x_launch_program_from_disk()  ; initial dual cores cpu support.
-        - gp2x_launch_subprogram()         ; initial dual cores cpu support.
-        - gp2x_blitter_rect15()            ; very basic blit function by popular demand ;-)
-        - gp2x_blitter_rect8()             ; very basic blit function by popular demand ;-)
-        - gp2x_video_hsync()               ; hsync waiting code (thanks Reesy)
-        - gp2x_video_vsync()               ; vsync waiting code (thanks Reesy)
-
-       fixed functions:
-        - gp2x_video_color8()              ; bugfixed a stupid typo (thanks Franxis for the bug report)
-
-  0.7: added functions:
-        - gp2x_sound_volume()
-
-       fixed functions:
-        - gp2x_deinit()           ; fixed menu launch code when exiting.
-
-       improved functions:
-        - gp2x_timer_read()       ; rewritten timer. it should be more accurate now.
-        - gp2x_init()             ; faster init code.
-
-  0.6: added functions:
-        - gp2x_timer_read()
-        - gp2x_sound_pause()
-
-       fixed functions:
-        - gp2x_video_setpalette() ; palette handling was incorrect. fixed.
-
-  0.5: improved functions:
-        - gp2x_init()             ; better and cleaner initalizing code.
-        - gp2x_init()             ; sound patched for real stereo output (by using NK's solution)
-
-  0.4: lots of cleanups.
-       sound is threaded and double buffered now.
-       8 bpp video support.
-
-       fixed functions:
-        - gp2x_deinit()           ; better and cleaner exiting code.
-
-  0.3: shorter library.
-
-       fixed functions:
-        - gp2x_joystick_read()    ; improved joystick diagonal detection.
-
-  0.2: better code layout.
-       public release.
-
-  0.1: beta release.
-*/
-
-#include "minimal.h"
-#include "squidgehack.h"
-#include "asmutils.h"
-
-         unsigned char  *gp2x_screen8                 ,*gp2x_upperRAM;
-         unsigned long   gp2x_dev[8]={0,0,0,0,0,0,0,0}, gp2x_physvram[8], *gp2x_memregl,       gp2x_volume,                      gp2x_ticks_per_second;
-volatile unsigned long   gp2x_sound_pausei=1,           gp2x_ticks=0,      gp2x_sound=0,      *gp2x_dualcore_ram=0;
-         unsigned short *gp2x_memregs,                 *gp2x_screen15,    *gp2x_logvram15[4],  gp2x_sound_buffer[4+((44100/25)*2)*8]; //25 Hz gives our biggest supported sampling buffer
-volatile unsigned short  gp2x_palette[512];
-
-extern void gp2x_sound_frame(void *blah, void *buff, int samples);
-
-// hack
-static int scaling_enabled = 0;
-
-void gp2x_video_flip(void)
-{
-  unsigned long address=gp2x_physvram[gp2x_physvram[7]];
-  if (scaling_enabled) address += 32;
-
-  // since we are using the mmu hack, we must flush the cache first
-  // (the params are most likely wrong, but they seem to work somehow)
-  flushcache(address, address + 320*240, 0);
-
-  if(++gp2x_physvram[7]==4) gp2x_physvram[7]=0;
-  gp2x_screen15=gp2x_logvram15[gp2x_physvram[7]];
-  gp2x_screen8=(unsigned char *)gp2x_screen15;
-
-  gp2x_memregs[0x290E>>1]=(unsigned short)(address & 0xFFFF);
-  gp2x_memregs[0x2910>>1]=(unsigned short)(address >> 16);
-  gp2x_memregs[0x2912>>1]=(unsigned short)(address & 0xFFFF);
-  gp2x_memregs[0x2914>>1]=(unsigned short)(address >> 16);
-}
-
-void gp2x_video_flip_single(void)
-{
-  unsigned long address=gp2x_physvram[0];
-
-  gp2x_screen15=gp2x_logvram15[0];
-  gp2x_screen8=(unsigned char *)gp2x_screen15;
-
-  gp2x_memregs[0x290E>>1]=(unsigned short)(address & 0xFFFF);
-  gp2x_memregs[0x2910>>1]=(unsigned short)(address >> 16);
-  gp2x_memregs[0x2912>>1]=(unsigned short)(address & 0xFFFF);
-  gp2x_memregs[0x2914>>1]=(unsigned short)(address >> 16);
-}
-
-
-void gp2x_video_setgamma(unsigned short gamma) /*0..255*/
-{
-  int i=256*3;
-  gp2x_memregs[0x295C>>1]=0;
-  while(i--) gp2x_memregs[0x295E>>1]=gamma;
-}
-
-void gp2x_video_setpalette(void)
-{
-  unsigned short *g=(unsigned short *)gp2x_palette; int i=512;
-  gp2x_memregs[0x2958>>1]=0;
-  while(i--) gp2x_memregs[0x295A>>1]=*g++;
-}
-
-void gp2x_blitter_rect15(gp2x_rect *r)
-{
- int x, y; unsigned short *data=r->data15, *offset=&gp2x_screen15[r->x+r->y*320];
-
- y=r->h; if(r->solid)
-         while(y--) { x=r->w; while(x--) *offset++=*data++; offset+=320-x; }
-         else
-         while(y--) { x=r->w; while(x--) { if(*data) *offset=*data; offset++, data++; }
-                      offset+=320-x; }
-}
-
-void gp2x_blitter_rect8(gp2x_rect *r)
-{
- int x, y; unsigned char *data=r->data8,   *offset=&gp2x_screen8[r->x+r->y*320];
-
- y=r->h; if(r->solid)
-         while(y--) { x=r->w; while(x--) *offset++=*data++; offset+=320-x; }
-         else
-         while(y--) { x=r->w; while(x--) { if(*data) *offset=*data; offset++, data++; }
-                      offset+=320-x; }
-}
-
-unsigned long gp2x_joystick_read(void)
-{
-  unsigned long value=(gp2x_memregs[0x1198>>1] & 0x00FF);
-
-  if(value==0xFD) value=0xFA;
-  if(value==0xF7) value=0xEB;
-  if(value==0xDF) value=0xAF;
-  if(value==0x7F) value=0xBE;
-
-  return ~((gp2x_memregs[0x1184>>1] & 0xFF00) | value | (gp2x_memregs[0x1186>>1] << 16));
-}
-
-void gp2x_sound_volume(int l, int r)
-{
- l=(((l*0x50)/100)<<8)|((r*0x50)/100);          //0x5A, 0x60
- ioctl(gp2x_dev[4], SOUND_MIXER_WRITE_PCM, &l); //SOUND_MIXER_WRITE_VOLUME
-}
-
-void gp2x_timer_delay(unsigned long ticks)
-{
- unsigned long target=gp2x_memregl[0x0A00>>2]+ticks*gp2x_ticks_per_second;
- while(gp2x_memregl[0x0A00>>2]<target);
-}
-
-unsigned long gp2x_timer_read(void)
-{
- return gp2x_memregl[0x0A00>>2]/gp2x_ticks_per_second;
-}
-
-unsigned long gp2x_timer_read_ms(void)
-{
- return gp2x_memregl[0x0A00>>2];
-}
-
-
-void gp2x_sound_pause(int yes) { gp2x_sound_pausei=yes; }
-
-#if 0
-static void *gp2x_sound_play(void *blah)
-{
-  int flip=0, flyp=gp2x_sound_buffer[1];
-  struct timespec ts; ts.tv_sec=0, ts.tv_nsec=gp2x_sound_buffer[2];
-
-  while(!gp2x_sound)
-  {
-    nanosleep(&ts, NULL);
-
-
-   if(!gp2x_sound_pausei)
-   {
-     // [1] is sound buffer size     at 22050, 16, stereo, it is 1468 (367*4)
-     // [0] number of bytes?,  at 22050,16,stereo, it is 367
-     // first half of buffer
-
-     // first one is 368
-
-
-    gp2x_sound_frame(blah, (void *)(&gp2x_sound_buffer[4+flip]), gp2x_sound_buffer[0]);
-    // write out to second half of buffer
-    write(gp2x_dev[3],     (void *)(&gp2x_sound_buffer[4+flyp]), gp2x_sound_buffer[1]);
-
-    flip+=gp2x_sound_buffer[1];
-         if(flip==gp2x_sound_buffer[1]*8) flip=0;
-   flyp+=gp2x_sound_buffer[1];
-   if(flyp==gp2x_sound_buffer[1]*8) flyp=0;
-   }
-  }
-  return NULL;
-}
-#endif
-
-#if 0
-static void gp2x_initqueue(gp2x_queue *q, unsigned long queue_items, unsigned long *position920t, unsigned long *position940t)
-{
-  q->head  = q->tail  = q->items = 0;
-  q->max_items = queue_items;
-  if(position920t) q->place920t=position920t; else q->place920t=(unsigned long *)malloc(sizeof(unsigned long) * queue_items);
-  if(position940t) q->place940t=position940t;
-  memset(q->place920t, 0, sizeof(unsigned long) * queue_items);
-}
-
-static void gp2x_enqueue(gp2x_queue *q, unsigned long data)
-{
-  while(q->items==q->max_items); /*waiting for tail to decrease...*/
-  q->place920t[q->head = (q->head < q->max_items ? q->head+1 : 0)] = data;
-  q->items++;
-}
-
-/* UNUSED
- static unsigned long gp2x_dequeue(gp2x_queue *q)
-{
-  while(!q->items); //waiting for head to increase...
-  q->items--;
-  return q->place920t[q->tail = (q->tail < q->max_items ? q->tail+1 : 0)];
-} */
-#endif
-
-       void gp2x_dualcore_pause(int yes) { if(yes) gp2x_memregs[0x0904>>1] &= 0xFFFE; else gp2x_memregs[0x0904>>1] |= 1; }
-static void gp2x_940t_reset(int yes)     { gp2x_memregs[0x3B48>>1] = ((yes&1) << 7) | (0x03); }
-static void gp2x_940t_pause(int yes)     { gp2x_dualcore_pause(yes); }
-
-static void gp2x_dualcore_registers(int save)
-{
- static unsigned short regs[8];
-
- if(save)
- {
-  regs[0]=gp2x_memregs[0x0904>>1];  regs[1]=gp2x_memregs[0x0912>>1];
-  regs[2]=gp2x_memregs[0x091c>>1];  regs[3]=gp2x_memregs[0x3b40>>1];
-  regs[4]=gp2x_memregs[0x3b42>>1];  regs[5]=gp2x_memregs[0x3b48>>1];
-  regs[6]=gp2x_memregs[0x3b44>>1];  regs[7]=gp2x_memregs[0x3b46>>1];
-
-  gp2x_940t_reset(1);
-  gp2x_940t_pause(1);
- }
- else
- {
-  gp2x_memregs[0x0904>>1]=regs[0];  gp2x_memregs[0x0912>>1]=regs[1];
-  gp2x_memregs[0x091c>>1]=regs[2];  gp2x_memregs[0x3b40>>1]=regs[3];
-  gp2x_memregs[0x3b42>>1]=regs[4];  gp2x_memregs[0x3b48>>1]=regs[5];
-  gp2x_memregs[0x3b44>>1]=regs[6];  gp2x_memregs[0x3b46>>1]=regs[7];
- }
-}
-
-#if 0
-void gp2x_dualcore_sync(void)
-{
-  gp2x_queue *q=(gp2x_queue *)gp2x_1stcore_data_ptr(GP2X_QUEUE_ARRAY_PTR);
-  while(q->items);
-}
-
-void gp2x_dualcore_exec(unsigned long command) { gp2x_enqueue((gp2x_queue *)gp2x_1stcore_data_ptr(GP2X_QUEUE_ARRAY_PTR),command); }
-
-void gp2x_dualcore_launch_program(unsigned long *area, unsigned long size)
-{
-  unsigned long i=0, *arm940t_ram=(unsigned long *)gp2x_dualcore_ram;
-
-  gp2x_940t_reset(1);
-
-  gp2x_memregs[0x3B40>>1] = 0;                               //disable interrupts
-  gp2x_memregs[0x3B42>>1] = 0;
-  gp2x_memregs[0x3B44>>1] = 0xffff;
-  gp2x_memregs[0x3B46>>1] = 0xffff;
-
-  gp2x_940t_pause(0);
-
-  while(i < size) *arm940t_ram++=area[i++];
-
-  gp2x_initqueue((gp2x_queue *)gp2x_1stcore_data_ptr(GP2X_QUEUE_ARRAY_PTR), GP2X_QUEUE_MAX_ITEMS, (unsigned long *)gp2x_1stcore_data_ptr(GP2X_QUEUE_DATA_PTR), (unsigned long *)gp2x_2ndcore_data_ptr(GP2X_QUEUE_DATA_PTR));
-
-  gp2x_940t_reset(0);
-}
-
-void gp2x_dualcore_launch_program_from_disk(const char *file, unsigned long offset, unsigned long size)
-{
- FILE *in; void *data;
-
- if((in=fopen(file, "rb"))==NULL) return;
- if((data=malloc(size))==NULL) { fclose(in); return; }
- fseek(in, 0L, offset);
- fread(data, 1, size, in);
- gp2x_dualcore_launch_program((unsigned long *)data, size);
- free(data);
- fclose(in);
-}
-#endif
-
-void gp2x_init(int ticks_per_second, int bpp, int rate, int bits, int stereo, int Hz)
-{
-  struct fb_fix_screeninfo fixed_info;
-  static int first=1;
-
-  // GP2X_DO_SOUND
-  int gp2x_do_sound=1;
-  int frag=0;
-  int channels=1;
-  int stereoLocal=0;
-  int ret;
-
-  gp2x_ticks_per_second=7372800/ticks_per_second;
-
-  if(!gp2x_dev[0])   gp2x_dev[0] = open("/dev/fb0",   O_RDWR);
-  if(!gp2x_dev[1])   gp2x_dev[1] = open("/dev/fb1",   O_RDWR);
-  if(!gp2x_dev[2])   gp2x_dev[2] = open("/dev/mem",   O_RDWR);
-
-  ioctl(gp2x_dev[gp2x_physvram[7]=0], FBIOGET_FSCREENINFO, &fixed_info);
-   gp2x_physvram[2]=gp2x_physvram[0]=fixed_info.smem_start;
-   gp2x_screen15=gp2x_logvram15[2]=gp2x_logvram15[0]=
-    (unsigned short *)mmap(0, 0x20000*2, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], gp2x_physvram[0]);
-                                        gp2x_screen8=(unsigned char *)gp2x_screen15;
-  printf("/dev/fb0 is @ %08lx / %p\n", gp2x_physvram[0], gp2x_screen15);
-
-  ioctl(gp2x_dev[1], FBIOGET_FSCREENINFO, &fixed_info);
-   gp2x_physvram[3]=gp2x_physvram[1]=fixed_info.smem_start;
-   gp2x_logvram15[3]=gp2x_logvram15[1]=
-    (unsigned short *)mmap(0, 0x20000*2, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], gp2x_physvram[1]);
-  printf("/dev/fb1 is @ %08lx / %p\n", gp2x_physvram[1], gp2x_logvram15[1]);
-
-  // apply the MMU hack
-  ret = mmuhack();
-  printf("squidge hack code finished and returned %s\n", ret ? "ok" : "fail");
-
-  // don't run sound right now
-  if ( gp2x_do_sound)
-  {
-    if(!gp2x_dev[3])   gp2x_dev[3] = open("/dev/dsp",   O_WRONLY|O_ASYNC);
-    if(!gp2x_dev[4])   gp2x_dev[4] = open("/dev/mixer", O_RDWR);
-  }
-
-//  gp2x_dualcore_ram=(unsigned long  *)mmap(0, 0x1000000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0x03000000);
-/*gp2x_dualcore_ram=(unsigned long  *)mmap(0, 0x2000000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0x02000000);*/
-       gp2x_memregl=(unsigned long  *)mmap(0, 0x10000,   PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0xc0000000);
-        gp2x_memregs=(unsigned short *)gp2x_memregl;
-
-  if(first) { printf(MINILIB_VERSION "\n");
-              gp2x_dualcore_registers(1);
-              gp2x_sound_volume(100,100);
-              gp2x_memregs[0x0F16>>1] = 0x830a; usleep(100000);
-              gp2x_memregs[0x0F58>>1] = 0x100c; usleep(100000); }
-
-  gp2x_memregs[0x28DA>>1]=(((bpp+1)/8)<<9)|0xAB; /*8/15/16/24bpp...*/
-  gp2x_memregs[0x290C>>1]=320*((bpp+1)/8);       /*line width in bytes*/
-
-  memset(gp2x_screen15, 0, 320*240*2); gp2x_video_flip();
-  memset(gp2x_screen15, 0, 320*240*2); gp2x_video_flip();
-
-  //if(bpp==8)  gp2x_physvram[2]+=320*240,    gp2x_physvram[3]+=320*240,
-  //           gp2x_logvram15[2]+=320*240/2, gp2x_logvram15[3]+=320*240/2;
-  if(bpp==8)  gp2x_physvram[2]+=0x20000,   gp2x_physvram[3]+=0x20000,
-             gp2x_logvram15[2]+=0x20000/2, gp2x_logvram15[3]+=0x20000/2;
-
-
- if ( gp2x_do_sound)
- {
-    ioctl(gp2x_dev[3], SNDCTL_DSP_SPEED,  &rate);
-    ioctl(gp2x_dev[3], SNDCTL_DSP_SETFMT, &bits);
-
-    ioctl(gp2x_dev[3], SNDCTL_DSP_CHANNELS, &channels);
-    ioctl(gp2x_dev[3], SNDCTL_DSP_STEREO, &stereoLocal);
-
-    frag = 0x40000|13;
-    ioctl(gp2x_dev[3], SNDCTL_DSP_SETFRAGMENT, &frag);
-
-    {
-       // calculate buffer size
-       int frag = 0, bsize, buffers = 16;
-       bsize = rate / 32;
-       if (rate > 22050) { bsize*=4; buffers*=2; } // 44k mode seems to be very demanding
-       while ((bsize>>=1)) frag++;
-       frag |= buffers<<16; // 16 buffers
-       ioctl(gp2x_dev[3], SNDCTL_DSP_SETFRAGMENT, &frag);
-       printf("gp2x_set_sound: %i/%ibit/%s, %i buffers of %i bytes\n",
-               rate, bits, stereo?"stereo":"mono", frag>>16, 1<<(frag&0xffff));
-    }
-
-    if(first)
-    {
-      first=0;
-    }
-  }
-}
-
-
-extern int fcloseall(void);
-void gp2x_deinit(void)
-{
-  while((gp2x_sound++)<1000000);                               //wait arm920t threads to finish
-
-  gp2x_dualcore_registers(0);
-  mmuunhack();
-
-  gp2x_memregs[0x28DA>>1]=0x4AB;                               //set video mode
-  gp2x_memregs[0x290C>>1]=640;
-
-  { int i; for(i=0;i<8;i++) if(gp2x_dev[i]) close(gp2x_dev[i]); }    //close all devices
-
-  fcloseall();                                                   //close all files
-
-}
-
-
-void SetVideoScaling(int pixels,int width,int height)
-{
-        float x, y;
-        float xscale,yscale=0;
-
-        int bpp=(gp2x_memregs[0x28DA>>1]>>9)&0x3;  /* bytes per pixel */
-
-       scaling_enabled = (width == 320) ? 0 : 1;
-
-        if(gp2x_memregs[0x2800>>1]&0x100) /* TV-Out ON? */
-        {
-                xscale=489.0; /* X-Scale with TV-Out (PAL or NTSC) */
-                if (gp2x_memregs[0x2818>>1]  == 287) /* PAL? */
-                        yscale=(pixels*274.0)/320.0; /* Y-Scale with PAL */
-                else if (gp2x_memregs[0x2818>>1]  == 239) /* NTSC? */
-                        yscale=(pixels*331.0)/320.0; /* Y-Scale with NTSC */
-        }
-        else /* TV-Out OFF? */
-        {
-                xscale=1024.0; /* X-Scale for LCD */
-                yscale=pixels; /* Y-Scale for LCD */
-        }
-
-        x=(xscale*width)/320.0;
-        y=(yscale*bpp*height)/240.0;
-        gp2x_memregs[0x2906>>1]=(unsigned short)x; /* scale horizontal */
-        gp2x_memregl[0x2908>>2]=(unsigned  long)y; /* scale vertical */
-        gp2x_memregs[0x290C>>1]=pixels*bpp; /* Set Video Width */
-}
+/**\r
+ * This is a rewrite of a subset of rlyeh's minimal library.\r
+**/\r
+\r
+/*\r
+\r
+  GP2X minimal library v0.A by rlyeh, (c) 2005. emulnation.info@rlyeh (swap it!)\r
+\r
+  Thanks to Squidge, Robster, snaff, Reesy and NK, for the help & previous work! :-)\r
+\r
+  License\r
+  =======\r
+\r
+  Free for non-commercial projects (it would be nice receiving a mail from you).\r
+  Other cases, ask me first.\r
+\r
+  GamePark Holdings is not allowed to use this library and/or use parts from it.\r
+\r
+*/\r
+\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+#include <sys/mman.h>\r
+#include <sys/types.h>\r
+#include <sys/stat.h>\r
+#include <sys/ioctl.h>\r
+#include <sys/soundcard.h>\r
+#include <fcntl.h>\r
+#include <errno.h>\r
+\r
+#include "minimal.h"\r
+#include "usbjoy.h"\r
+#include "asmutils.h"\r
+\r
+volatile unsigned short *gp2x_memregs;\r
+//static\r
+volatile unsigned long  *gp2x_memregl;\r
+static void *gp2x_screens[4];\r
+static int screensel = 0;\r
+//static\r
+int memdev = 0;\r
+static int sounddev = 0, mixerdev = 0;\r
+\r
+void *gp2x_screen;\r
+\r
+#define FRAMEBUFF_WHOLESIZE (0x30000*4) // 320*240*2 + some more\r
+#define FRAMEBUFF_ADDR0 (0x4000000-FRAMEBUFF_WHOLESIZE)\r
+#define FRAMEBUFF_ADDR1 (FRAMEBUFF_ADDR0+0x30000)\r
+#define FRAMEBUFF_ADDR2 (FRAMEBUFF_ADDR1+0x30000)\r
+#define FRAMEBUFF_ADDR3 (FRAMEBUFF_ADDR2+0x30000)\r
+\r
+static const int gp2x_screenaddrs[4] = { FRAMEBUFF_ADDR0, FRAMEBUFF_ADDR1, FRAMEBUFF_ADDR2, FRAMEBUFF_ADDR3 };\r
+static int gp2x_screenaddrs_use[4];\r
+static unsigned short gp2x_screenaddr_old[4];\r
+\r
+\r
+// hack to simplify thing for fceu\r
+static int scaling_enabled = 0;\r
+\r
+/* video stuff */\r
+void gp2x_video_flip(void)\r
+{\r
+       unsigned short lsw, msw;\r
+       int addr = gp2x_screenaddrs_use[screensel&3];\r
+\r
+       if (scaling_enabled) addr += 32;\r
+\r
+       // since we are using the mmu hack, we must flush the cache first\r
+       // (the params are most likely wrong, but they seem to work somehow)\r
+       flushcache(addr, addr + 320*240*2, 0);\r
+\r
+       lsw = (unsigned short) addr;\r
+       msw = (unsigned short)(addr >> 16);\r
+\r
+       gp2x_memregs[0x2910>>1] = msw;\r
+       gp2x_memregs[0x2914>>1] = msw;\r
+       gp2x_memregs[0x290E>>1] = lsw;\r
+       gp2x_memregs[0x2912>>1] = lsw;\r
+\r
+       // jump to other buffer:\r
+       gp2x_screen = gp2x_screens[++screensel&3];\r
+}\r
+\r
+/* doulblebuffered flip */\r
+void gp2x_video_flip2(void)\r
+{\r
+       unsigned short msw = (unsigned short)(gp2x_screenaddrs_use[screensel&1] >> 16);\r
+\r
+       gp2x_memregs[0x2910>>1] = msw;\r
+       gp2x_memregs[0x2914>>1] = msw;\r
+       gp2x_memregs[0x290E>>1] = 0;\r
+       gp2x_memregs[0x2912>>1] = 0;\r
+\r
+       // jump to other buffer:\r
+       gp2x_screen = gp2x_screens[++screensel&1];\r
+}\r
+\r
+\r
+void gp2x_video_changemode2(int bpp)\r
+{\r
+       gp2x_memregs[0x28DA>>1]=(((bpp+1)/8)<<9)|0xAB; /*8/15/16/24bpp...*/\r
+       gp2x_memregs[0x290C>>1]=320*((bpp+1)/8); /*line width in bytes*/\r
+}\r
+\r
+\r
+void gp2x_video_changemode(int bpp)\r
+{\r
+       gp2x_video_changemode2(bpp);\r
+\r
+       gp2x_memset_all_buffers(0, 0, 320*240*2);\r
+       gp2x_video_flip();\r
+}\r
+\r
+\r
+void gp2x_video_setpalette(int *pal, int len)\r
+{\r
+       unsigned short *g=(unsigned short *)pal;\r
+       volatile unsigned short *memreg = &gp2x_memregs[0x295A>>1];\r
+       gp2x_memregs[0x2958>>1] = 0;\r
+\r
+       len *= 2;\r
+       while(len--) *memreg=*g++;\r
+}\r
+\r
+\r
+// TV Compatible function //\r
+void gp2x_video_RGB_setscaling(int ln_offs, int W, int H)\r
+{\r
+       float escalaw, escalah;\r
+       int bpp = (gp2x_memregs[0x28DA>>1]>>9)&0x3;\r
+       unsigned short scalw;\r
+\r
+       // fceu hack\r
+       scaling_enabled = (W == 320) ? 0 : 1;\r
+\r
+       // set offset\r
+       gp2x_screenaddrs_use[0] = gp2x_screenaddrs[0] + ln_offs * 320 * bpp;\r
+       gp2x_screenaddrs_use[1] = gp2x_screenaddrs[1] + ln_offs * 320 * bpp;\r
+       gp2x_screenaddrs_use[2] = gp2x_screenaddrs[2] + ln_offs * 320 * bpp;\r
+       gp2x_screenaddrs_use[3] = gp2x_screenaddrs[3] + ln_offs * 320 * bpp;\r
+\r
+       escalaw = 1024.0; // RGB Horiz LCD\r
+       escalah = 320.0; // RGB Vert LCD\r
+\r
+       if(gp2x_memregs[0x2800>>1]&0x100) //TV-Out\r
+       {\r
+               escalaw=489.0; // RGB Horiz TV (PAL, NTSC)\r
+               if (gp2x_memregs[0x2818>>1]  == 287) //PAL\r
+                       escalah=274.0; // RGB Vert TV PAL\r
+               else if (gp2x_memregs[0x2818>>1]  == 239) //NTSC\r
+                       escalah=331.0; // RGB Vert TV NTSC\r
+       }\r
+\r
+       // scale horizontal\r
+       scalw = (unsigned short)((float)escalaw *(W/320.0));\r
+       /* if there is no horizontal scaling, vertical doesn't work. Here is a nasty wrokaround... */\r
+       if (H != 240 && W == 320) scalw--;\r
+       gp2x_memregs[0x2906>>1]=scalw;\r
+       // scale vertical\r
+       gp2x_memregl[0x2908>>2]=(unsigned long)((float)escalah *bpp *(H/240.0));\r
+}\r
+\r
+\r
+void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len)\r
+{\r
+       if (buffers & (1<<0)) memcpy((char *)gp2x_screens[0] + offset, data, len);\r
+       if (buffers & (1<<1)) memcpy((char *)gp2x_screens[1] + offset, data, len);\r
+       if (buffers & (1<<2)) memcpy((char *)gp2x_screens[2] + offset, data, len);\r
+       if (buffers & (1<<3)) memcpy((char *)gp2x_screens[3] + offset, data, len);\r
+}\r
+\r
+\r
+void gp2x_memcpy_all_buffers(void *data, int offset, int len)\r
+{\r
+       gp2x_memcpy_buffers(0xf, data, offset, len);\r
+}\r
+\r
+\r
+void gp2x_memset_all_buffers(int offset, int byte, int len)\r
+{\r
+       memset((char *)gp2x_screens[0] + offset, byte, len);\r
+       memset((char *)gp2x_screens[1] + offset, byte, len);\r
+       memset((char *)gp2x_screens[2] + offset, byte, len);\r
+       memset((char *)gp2x_screens[3] + offset, byte, len);\r
+}\r
+\r
+\r
+unsigned long gp2x_joystick_read(int allow_usb_joy)\r
+{\r
+       int i;\r
+       unsigned long value=(gp2x_memregs[0x1198>>1] & 0x00FF);\r
+       if(value==0xFD) value=0xFA;\r
+       if(value==0xF7) value=0xEB;\r
+       if(value==0xDF) value=0xAF;\r
+       if(value==0x7F) value=0xBE;\r
+       value = ~((gp2x_memregs[0x1184>>1] & 0xFF00) | value | (gp2x_memregs[0x1186>>1] << 16));\r
+\r
+       if (allow_usb_joy && num_of_joys > 0) {\r
+               // check the usb joy as well..\r
+               gp2x_usbjoy_update();\r
+               for (i = 0; i < num_of_joys; i++)\r
+                       value |= gp2x_usbjoy_check(i);\r
+       }\r
+\r
+       return value;\r
+}\r
+\r
+static int s_oldrate = 0, s_oldbits = 0, s_oldstereo = 0;\r
+\r
+void gp2x_start_sound(int rate, int bits, int stereo)\r
+{\r
+       int frag = 0, bsize, buffers;\r
+\r
+       // if no settings change, we don't need to do anything\r
+       if (rate == s_oldrate && s_oldbits == bits && s_oldstereo == stereo) return;\r
+\r
+       if (sounddev > 0) close(sounddev);\r
+       sounddev = open("/dev/dsp", O_WRONLY|O_ASYNC);\r
+       if (sounddev == -1)\r
+               printf("open(\"/dev/dsp\") failed with %i\n", errno);\r
+\r
+       ioctl(sounddev, SNDCTL_DSP_SPEED,  &rate);\r
+       ioctl(sounddev, SNDCTL_DSP_SETFMT, &bits);\r
+       ioctl(sounddev, SNDCTL_DSP_STEREO, &stereo);\r
+       // calculate buffer size\r
+       buffers = 16;\r
+       bsize = rate / 32;\r
+       if (rate > 22050) { bsize*=4; buffers*=2; } // 44k mode seems to be very demanding\r
+       while ((bsize>>=1)) frag++;\r
+       frag |= buffers<<16; // 16 buffers\r
+       ioctl(sounddev, SNDCTL_DSP_SETFRAGMENT, &frag);\r
+       printf("gp2x_set_sound: %i/%ibit/%s, %i buffers of %i bytes\n",\r
+               rate, bits, stereo?"stereo":"mono", frag>>16, 1<<(frag&0xffff));\r
+\r
+       s_oldrate = rate; s_oldbits = bits; s_oldstereo = stereo;\r
+       usleep(100000);\r
+}\r
+\r
+\r
+void gp2x_sound_write(void *buff, int len)\r
+{\r
+       write(sounddev, buff, len);\r
+}\r
+\r
+void gp2x_sound_sync(void)\r
+{\r
+       ioctl(sounddev, SOUND_PCM_SYNC, 0);\r
+}\r
+\r
+void gp2x_sound_volume(int l, int r)\r
+{\r
+       l=l<0?0:l; l=l>255?255:l; r=r<0?0:r; r=r>255?255:r;\r
+       l<<=8; l|=r;\r
+       ioctl(mixerdev, SOUND_MIXER_WRITE_PCM, &l); /*SOUND_MIXER_WRITE_VOLUME*/\r
+}\r
+\r
+\r
+/* common */\r
+void gp2x_init(void)\r
+{\r
+       printf("entering init()\n"); fflush(stdout);\r
+\r
+       memdev = open("/dev/mem", O_RDWR);\r
+       if (memdev == -1)\r
+       {\r
+               printf("open(\"/dev/mem\") failed with %i\n", errno);\r
+               exit(1);\r
+       }\r
+\r
+       gp2x_memregs = mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);\r
+       printf("memregs are @ %p\n", gp2x_memregs);\r
+       if(gp2x_memregs == MAP_FAILED)\r
+       {\r
+               printf("mmap(memregs) failed with %i\n", errno);\r
+               exit(1);\r
+       }\r
+       gp2x_memregl = (unsigned long *) gp2x_memregs;\r
+\r
+       gp2x_screens[0] = mmap(0, FRAMEBUFF_WHOLESIZE, PROT_WRITE, MAP_SHARED, memdev, FRAMEBUFF_ADDR0);\r
+       if(gp2x_screens[0] == MAP_FAILED)\r
+       {\r
+               printf("mmap(gp2x_screen) failed with %i\n", errno);\r
+               exit(1);\r
+       }\r
+       printf("framebuffers point to %p\n", gp2x_screens[0]);\r
+       gp2x_screens[1] = (char *) gp2x_screens[0]+0x30000;\r
+       gp2x_screens[2] = (char *) gp2x_screens[1]+0x30000;\r
+       gp2x_screens[3] = (char *) gp2x_screens[2]+0x30000;\r
+\r
+       gp2x_screen = gp2x_screens[0];\r
+       screensel = 0;\r
+\r
+       gp2x_screenaddr_old[0] = gp2x_memregs[0x290E>>1];\r
+       gp2x_screenaddr_old[1] = gp2x_memregs[0x2910>>1];\r
+       gp2x_screenaddr_old[2] = gp2x_memregs[0x2912>>1];\r
+       gp2x_screenaddr_old[3] = gp2x_memregs[0x2914>>1];\r
+\r
+       memcpy(gp2x_screenaddrs_use, gp2x_screenaddrs, sizeof(gp2x_screenaddrs));\r
+       gp2x_memset_all_buffers(0, 0, 320*240*2);\r
+\r
+       // snd\r
+       mixerdev = open("/dev/mixer", O_RDWR);\r
+       if (mixerdev == -1)\r
+               printf("open(\"/dev/mixer\") failed with %i\n", errno);\r
+\r
+       /* init usb joys -GnoStiC */\r
+       gp2x_usbjoy_init();\r
+\r
+       printf("exitting init()\n"); fflush(stdout);\r
+}\r
+\r
+char *ext_menu = 0, *ext_state = 0;\r
+\r
+void gp2x_deinit(void)\r
+{\r
+       gp2x_video_changemode(15);\r
+       gp2x_memregs[0x290E>>1] = gp2x_screenaddr_old[0];\r
+       gp2x_memregs[0x2910>>1] = gp2x_screenaddr_old[1];\r
+       gp2x_memregs[0x2912>>1] = gp2x_screenaddr_old[2];\r
+       gp2x_memregs[0x2914>>1] = gp2x_screenaddr_old[3];\r
+\r
+       munmap(gp2x_screens[0], FRAMEBUFF_WHOLESIZE);\r
+       munmap((void *)gp2x_memregs, 0x10000);\r
+       close(memdev);\r
+       close(mixerdev);\r
+       if (sounddev > 0) close(sounddev);\r
+\r
+       gp2x_usbjoy_deinit();\r
+\r
+       printf("all done, running ");\r
+\r
+       // Zaq121's alternative frontend support from MAME\r
+       if(ext_menu && ext_state) {\r
+               printf("%s -state %s\n", ext_menu, ext_state);\r
+               execl(ext_menu, ext_menu, "-state", ext_state, NULL);\r
+       } else if(ext_menu) {\r
+               printf("%s\n", ext_menu);\r
+               execl(ext_menu, ext_menu, NULL);\r
+       } else {\r
+               printf("gp2xmenu\n");\r
+               chdir("/usr/gp2x");\r
+               execl("gp2xmenu", "gp2xmenu", NULL);\r
+       }\r
+}\r
+\r
+\r