partially working menu
authornotaz <notasas@gmail.com>
Thu, 10 May 2007 22:31:19 +0000 (22:31 +0000)
committernotaz <notasas@gmail.com>
Thu, 10 May 2007 22:31:19 +0000 (22:31 +0000)
git-svn-id: file:///home/notaz/opt/svn/fceu@127 be3aeb3a-fb24-0410-a615-afba39da0efa

27 files changed:
Makefile.gp2x
bench.txt
drivers/common/args.c
drivers/common/args.h
drivers/gp2x/asmutils.h
drivers/gp2x/asmutils.s
drivers/gp2x/cpuctrl.c [new file with mode: 0644]
drivers/gp2x/cpuctrl.h [new file with mode: 0644]
drivers/gp2x/dface.h
drivers/gp2x/fonts.c [new file with mode: 0644]
drivers/gp2x/fonts.h [new file with mode: 0644]
drivers/gp2x/gp2x-sound.c
drivers/gp2x/gp2x-video.c
drivers/gp2x/gp2x.c
drivers/gp2x/gp2x.h
drivers/gp2x/input.c
drivers/gp2x/main.c
drivers/gp2x/main.h
drivers/gp2x/menu.c [new file with mode: 0644]
drivers/gp2x/menu.h [new file with mode: 0644]
drivers/gp2x/minimal.c
drivers/gp2x/minimal.h
drivers/gp2x/minimal_940t.h [deleted file]
drivers/gp2x/throttle.c
drivers/gp2x/usbjoy.c [new file with mode: 0644]
drivers/gp2x/usbjoy.h [new file with mode: 0644]
fce.c

index 137b353..a86f8c5 100644 (file)
@@ -28,10 +28,10 @@ gpfce: fceu
 
 include zlib/Makefile
 
 
 include zlib/Makefile
 
-OBJDRIVER       = ${B}minimal.o ${B}squidgehack.o ${B}asmutils.o ${B}gp2x.o ${B}main.o ${B}throttle.o \
-               ${B}unix-netplay.o ${B}gp2x-sound.o ${B}gp2x-video.o ${B}lnx-joystick.o \
+OBJDRIVER       = ${B}minimal.o ${B}cpuctrl.o ${B}squidgehack.o ${B}asmutils.o ${B}gp2x.o ${B}main.o ${B}throttle.o \
+               ${B}unix-netplay.o ${B}gp2x-sound.o ${B}gp2x-video.o ${B}lnx-joystick.o ${B}usbjoy.o ${B}menu.o ${B}fonts.o \
                drivers/common/cheat.o drivers/common/config.o drivers/common/args.o drivers/common/vidblit.o ${UNZIPOBJS} ppu.o movie.o
                drivers/common/cheat.o drivers/common/config.o drivers/common/args.o drivers/common/vidblit.o ${UNZIPOBJS} ppu.o movie.o
-LDRIVER                += -L /mnt/sd/lib  -L/mnt/sd/gp2x/usr/lib -lm -lz -static -Wl,-Map=fceu.map
+LDRIVER                += -L /mnt/sd/lib -L/mnt/sd/gp2x/usr/lib -lm -lz -static -Wl,-Map=fceu.map
 
 ifeq ($(asm_6502),1)
 TFLAGS  += -DASM_6502
 
 ifeq ($(asm_6502),1)
 TFLAGS  += -DASM_6502
index 1121918..b4605c5 100644 (file)
--- a/bench.txt
+++ b/bench.txt
@@ -17,4 +17,5 @@ v03+merge
 smb 95-96
 bm 86-87
 kage 82-83
 smb 95-96
 bm 86-87
 kage 82-83
+grad 72-73
 
 
index 7c6c8fe..964d931 100644 (file)
 #include "../../types.h"
 #include "args.h"
 
 #include "../../types.h"
 #include "args.h"
 
-void ParseEA(int x, int argc, char *argv[], ARGPSTRUCT *argsps)
+static int ParseEA(int x, int argc, char *argv[], ARGPSTRUCT *argsps)
 {
 {
-  int y=0;
+  int y=0,ret=0;
 
   do
   {
    if(!argsps[y].name)
    {
 
   do
   {
    if(!argsps[y].name)
    {
-    ParseEA(x,argc,argv,(void *)argsps[y].var);
+    ret = ParseEA(x,argc,argv,(void *)argsps[y].var);
     y++;
     continue;
    }
     y++;
     continue;
    }
@@ -50,7 +50,7 @@ void ParseEA(int x, int argc, char *argv[], ARGPSTRUCT *argsps)
     if(argsps[y].subs)
     {
      if((x+1)>=argc)
     if(argsps[y].subs)
     {
      if((x+1)>=argc)
-      break;
+      return 0;
      if(argsps[y].substype&0x8000)
      {
       *(int *)argsps[y].subs&=~(argsps[y].substype&(~0x8000));
      if(argsps[y].substype&0x8000)
      {
       *(int *)argsps[y].subs&=~(argsps[y].substype&(~0x8000));
@@ -69,23 +69,34 @@ void ParseEA(int x, int argc, char *argv[], ARGPSTRUCT *argsps)
                free(*(char **)argsps[y].subs);
               if(!( *(char **)argsps[y].subs=malloc(strlen(argv[x+1])+1) ))
                break;
                free(*(char **)argsps[y].subs);
               if(!( *(char **)argsps[y].subs=malloc(strlen(argv[x+1])+1) ))
                break;
-             } 
+             }
              strcpy(*(char **)argsps[y].subs,argv[x+1]);
              break;
       }
              strcpy(*(char **)argsps[y].subs,argv[x+1]);
              break;
       }
+     ret=2;
     }
     }
-    if(argsps[y].var)
+    else if(argsps[y].var)
+    {
      *argsps[y].var=1;
      *argsps[y].var=1;
+     ret=1;
+    }
    }
    y++;
   } while(argsps[y].var || argsps[y].subs);
    }
    y++;
   } while(argsps[y].var || argsps[y].subs);
+  return ret;
 }
 
 }
 
-void ParseArguments(int argc, char *argv[], ARGPSTRUCT *argsps)
+/* returns 1 if last arg was usccessfully parsed */
+int ParseArguments(int argc, char *argv[], ARGPSTRUCT *argsps)
 {
 {
- int x;
+ int x, ret=0;
 
  for(x=0;x<argc;x++)
 
  for(x=0;x<argc;x++)
-  ParseEA(x,argc,argv,argsps);
+ {
+  ret = ParseEA(x,argc,argv,argsps);
+  if (ret == 2) x++;
+ }
+
+ return ret;
 }
 
 }
 
index 426aa63..9ac2661 100644 (file)
@@ -26,5 +26,5 @@ typedef struct {
        int substype;
 } ARGPSTRUCT;
 
        int substype;
 } ARGPSTRUCT;
 
-void ParseArguments(int argc, char *argv[], ARGPSTRUCT *argsps);
+int ParseArguments(int argc, char *argv[], ARGPSTRUCT *argsps);
 
 
index 91dc24c..5f3d895 100644 (file)
@@ -1,4 +1,5 @@
 void flushcache(unsigned int beginning_addr, unsigned int end_addr, unsigned int flags);\r
 void block_or(void *src, size_t n, int pat);\r
 void block_andor(void *src, size_t n, int andpat, int orpat);\r
 void flushcache(unsigned int beginning_addr, unsigned int end_addr, unsigned int flags);\r
 void block_or(void *src, size_t n, int pat);\r
 void block_andor(void *src, size_t n, int andpat, int orpat);\r
+void spend_cycles(int c); // utility\r
 \r
 \r
index a7f123f..3db4e30 100644 (file)
@@ -54,6 +54,18 @@ block_loop_andor:
     bx      lr
 
 
     bx      lr
 
 
+.global spend_cycles @ c
+
+spend_cycles:
+    mov     r0, r0, lsr #2  @ 4 cycles/iteration
+    sub     r0, r0, #2      @ entry/exit/init
+.sc_loop:
+    subs    r0, r0, #1
+    bpl     .sc_loop
+
+    bx      lr
+
+
 
 /* buggy and slow, probably because function call overhead
 @ renderer helper, based on bitbank's method
 
 /* buggy and slow, probably because function call overhead
 @ renderer helper, based on bitbank's method
diff --git a/drivers/gp2x/cpuctrl.c b/drivers/gp2x/cpuctrl.c
new file mode 100644 (file)
index 0000000..7bbdb67
--- /dev/null
@@ -0,0 +1,156 @@
+/*  cpuctrl for GP2X
+    Copyright (C) 2005  Hermes/PS2Reality 
+       the gamma-routine was provided by theoddbot
+       parts (c) Rlyehs Work & (C) 2006 god_at_hell 
+
+    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 program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+
+#include <sys/mman.h>
+#include <math.h>
+#include "cpuctrl.h"
+
+
+/* system registers */
+static struct 
+{
+       unsigned short SYSCLKENREG,SYSCSETREG,FPLLVSETREG,DUALINT920,DUALINT940,DUALCTRL940,MEMTIMEX0,MEMTIMEX1;
+}
+system_reg;
+
+static unsigned short dispclockdiv;
+
+static volatile unsigned short *MEM_REG;
+
+#define SYS_CLK_FREQ 7372800
+
+
+void cpuctrl_init(void)
+{
+       extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */
+       MEM_REG=&gp2x_memregs[0];
+       system_reg.SYSCSETREG=MEM_REG[0x91c>>1];
+       system_reg.FPLLVSETREG=MEM_REG[0x912>>1];
+       system_reg.SYSCLKENREG=MEM_REG[0x904>>1];
+       system_reg.DUALINT920=MEM_REG[0x3B40>>1];
+       system_reg.DUALINT940=MEM_REG[0x3B42>>1];
+       system_reg.DUALCTRL940=MEM_REG[0x3B48>>1];
+       system_reg.MEMTIMEX0=MEM_REG[0x3802>>1];
+       system_reg.MEMTIMEX1=MEM_REG[0x3804>>1];
+       dispclockdiv=MEM_REG[0x924>>1];
+}
+
+
+void cpuctrl_deinit(void)
+{
+       MEM_REG[0x91c>>1]=system_reg.SYSCSETREG;
+       MEM_REG[0x910>>1]=system_reg.FPLLVSETREG;
+       MEM_REG[0x3B40>>1]=system_reg.DUALINT920;
+       MEM_REG[0x3B42>>1]=system_reg.DUALINT940;
+       MEM_REG[0x3B48>>1]=system_reg.DUALCTRL940;
+       MEM_REG[0x904>>1]=system_reg.SYSCLKENREG;
+       MEM_REG[0x924>>1]=dispclockdiv;
+       MEM_REG[0x3802>>1]=system_reg.MEMTIMEX0;
+       MEM_REG[0x3804>>1]=system_reg.MEMTIMEX1 /*| 0x9000*/;
+}
+
+
+void set_display_clock_div(unsigned div)
+{
+       div=((div & 63) | 64)<<8;
+       MEM_REG[0x924>>1]=(MEM_REG[0x924>>1] & ~(255<<8)) | div;
+}
+
+
+void set_FCLK(unsigned MHZ)
+{
+       unsigned v;
+       unsigned mdiv,pdiv=3,scale=0;
+       MHZ*=1000000;
+       mdiv=(MHZ*pdiv)/SYS_CLK_FREQ;
+       mdiv=((mdiv-8)<<8) & 0xff00;
+       pdiv=((pdiv-2)<<2) & 0xfc;
+       scale&=3;
+       v=mdiv | pdiv | scale;
+       MEM_REG[0x910>>1]=v;
+}
+
+
+void set_920_Div(unsigned short div)
+{
+       unsigned short v;
+       v = MEM_REG[0x91c>>1] & (~0x3);
+       MEM_REG[0x91c>>1] = (div & 0x7) | v; 
+}
+
+
+void set_DCLK_Div( unsigned short div )
+{
+       unsigned short v;
+       v = (unsigned short)( MEM_REG[0x91c>>1] & (~(0x7 << 6)) );
+       MEM_REG[0x91c>>1] = ((div & 0x7) << 6) | v; 
+}
+
+/*
+void Disable_940(void)
+{
+       MEM_REG[0x3B42>>1];
+       MEM_REG[0x3B42>>1]=0;
+       MEM_REG[0x3B46>>1]=0xffff;      
+       MEM_REG[0x3B48>>1]|= (1 << 7);
+       MEM_REG[0x904>>1]&=0xfffe;
+}
+*/
+
+void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, int tRCD)
+{
+       tRC -= 1; tRAS -= 1; tWR -= 1; tMRD -= 1; tRFC -= 1; tRP -= 1; tRCD -= 1; // ???
+       MEM_REG[0x3802>>1] = ((tMRD & 0xF) << 12) | ((tRFC & 0xF) << 8) | ((tRP & 0xF) << 4) | (tRCD & 0xF);
+       MEM_REG[0x3804>>1] = /*0x9000 |*/ ((tRC & 0xF) << 8) | ((tRAS & 0xF) << 4) | (tWR & 0xF);
+}
+
+
+/*
+void gp2x_video_wait_vsync(void)
+{
+       MEM_REG[0x2846>>1]=(MEM_REG[0x2846>>1] | 0x20) & ~2;
+       while(!(MEM_REG[0x2846>>1] & 2));
+}
+*/
+
+void set_gamma(int g100)
+{
+       float gamma = (float) g100 / 100;
+       int i;
+       //printf ("set gamma = %f\r\n",gamma);
+       gamma = 1/gamma;
+
+    //enable gamma
+    MEM_REG[0x2880>>1]&=~(1<<12);
+
+    MEM_REG[0x295C>>1]=0;
+    for(i=0; i<256; i++)
+    {
+               unsigned char g;
+        unsigned short s;
+        g =(unsigned char)(255.0*pow(i/255.0,gamma));
+        s = (g<<8) | g;
+               MEM_REG[0x295E>>1]= s;
+        MEM_REG[0x295E>>1]= g;
+    }
+}
+
diff --git a/drivers/gp2x/cpuctrl.h b/drivers/gp2x/cpuctrl.h
new file mode 100644 (file)
index 0000000..5b482a5
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __CPUCTRL_H__
+#define __CPUCTRL_H__
+
+extern void cpuctrl_init(void); /* call this at first */
+extern void save_system_regs(void); /* save some registers */
+extern void cpuctrl_deinit(void);
+extern void set_display_clock_div(unsigned div);
+extern void set_FCLK(unsigned MHZ); /* adjust the clock frequency (in Mhz units) */
+extern void set_920_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+div)) */
+extern void set_DCLK_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+div)) */
+//extern void Disable_940(void); /* 940t down */
+//extern void gp2x_video_wait_vsync(void);
+extern void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, int tRCD);
+extern void set_gamma(int g100);
+
+#endif
index c4d2bfb..f2c569e 100644 (file)
@@ -7,6 +7,7 @@ void GetBaseDirectory(char *BaseDirectory);
 
 int InitSound(void);
 void WriteSound(int16 *Buffer, int Count);
 
 int InitSound(void);
 void WriteSound(int16 *Buffer, int Count);
+
 void KillSound(void);
 void SilenceSound(int s); /* DOS and SDL */
 
 void KillSound(void);
 void SilenceSound(int s); /* DOS and SDL */
 
diff --git a/drivers/gp2x/fonts.c b/drivers/gp2x/fonts.c
new file mode 100644 (file)
index 0000000..ea65481
--- /dev/null
@@ -0,0 +1,218 @@
+unsigned char fontdata8x8[64*16] =
+{
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x3C,0x42,0x99,0xBD,0xBD,0x99,0x42,0x3C,0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C,
+       0xFE,0x82,0x8A,0xD2,0xA2,0x82,0xFE,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00,
+       0x80,0xC0,0xF0,0xFC,0xF0,0xC0,0x80,0x00,0x01,0x03,0x0F,0x3F,0x0F,0x03,0x01,0x00,
+       0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0x00,0xEE,0xEE,0xEE,0xCC,0x00,0xCC,0xCC,0x00,
+       0x00,0x00,0x30,0x68,0x78,0x30,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00,
+       0x3C,0x66,0x7A,0x7A,0x7E,0x7E,0x3C,0x00,0x0E,0x3E,0x3A,0x22,0x26,0x6E,0xE4,0x40,
+       0x18,0x3C,0x7E,0x3C,0x3C,0x3C,0x3C,0x00,0x3C,0x3C,0x3C,0x3C,0x7E,0x3C,0x18,0x00,
+       0x08,0x7C,0x7E,0x7E,0x7C,0x08,0x00,0x00,0x10,0x3E,0x7E,0x7E,0x3E,0x10,0x00,0x00,
+       0x58,0x2A,0xDC,0xC8,0xDC,0x2A,0x58,0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00,
+       0x00,0x10,0x10,0x38,0x38,0x7C,0xFE,0x00,0xFE,0x7C,0x38,0x38,0x10,0x10,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x18,0x00,0x18,0x18,0x00,
+       0x6C,0x6C,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7C,0x28,0x7C,0x28,0x00,0x00,
+       0x10,0x38,0x60,0x38,0x0C,0x78,0x10,0x00,0x40,0xA4,0x48,0x10,0x24,0x4A,0x04,0x00,
+       0x18,0x34,0x18,0x3A,0x6C,0x66,0x3A,0x00,0x18,0x18,0x20,0x00,0x00,0x00,0x00,0x00,
+       0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x00,0x0C,0x06,0x06,0x06,0x06,0x06,0x0C,0x00,
+       0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00,
+       0x38,0x4C,0xC6,0xC6,0xC6,0x64,0x38,0x00,0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00,
+       0x7C,0xC6,0x0E,0x3C,0x78,0xE0,0xFE,0x00,0x7E,0x0C,0x18,0x3C,0x06,0xC6,0x7C,0x00,
+       0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x00,0xFC,0xC0,0xFC,0x06,0x06,0xC6,0x7C,0x00,
+       0x3C,0x60,0xC0,0xFC,0xC6,0xC6,0x7C,0x00,0xFE,0xC6,0x0C,0x18,0x30,0x30,0x30,0x00,
+       0x78,0xC4,0xE4,0x78,0x86,0x86,0x7C,0x00,0x7C,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00,
+       0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30,
+       0x1C,0x38,0x70,0xE0,0x70,0x38,0x1C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,
+       0x70,0x38,0x1C,0x0E,0x1C,0x38,0x70,0x00,0x7C,0xC6,0xC6,0x1C,0x18,0x00,0x18,0x00,
+       0x3C,0x42,0x99,0xA1,0xA5,0x99,0x42,0x3C,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00,
+       0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00,0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,
+       0xF8,0xCC,0xC6,0xC6,0xC6,0xCC,0xF8,0x00,0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xFE,0x00,
+       0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xC0,0x00,0x3E,0x60,0xC0,0xCE,0xC6,0x66,0x3E,0x00,
+       0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,
+       0x06,0x06,0x06,0x06,0xC6,0xC6,0x7C,0x00,0xC6,0xCC,0xD8,0xF0,0xF8,0xDC,0xCE,0x00,
+       0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00,
+       0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
+       0xFC,0xC6,0xC6,0xC6,0xFC,0xC0,0xC0,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x7A,0x00,
+       0xFC,0xC6,0xC6,0xCE,0xF8,0xDC,0xCE,0x00,0x78,0xCC,0xC0,0x7C,0x06,0xC6,0x7C,0x00,
+       0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
+       0xC6,0xC6,0xC6,0xEE,0x7C,0x38,0x10,0x00,0xC6,0xC6,0xD6,0xFE,0xFE,0xEE,0xC6,0x00,
+       0xC6,0xEE,0x3C,0x38,0x7C,0xEE,0xC6,0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00,
+       0xFE,0x0E,0x1C,0x38,0x70,0xE0,0xFE,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,
+       0x60,0x60,0x30,0x18,0x0C,0x06,0x06,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,
+       0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
+       0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0x66,0x3C,0x00,
+       0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x00,
+       0x06,0x3E,0x66,0x66,0x66,0x66,0x3E,0x00,0x00,0x3C,0x66,0x66,0x7E,0x60,0x3C,0x00,
+       0x1C,0x30,0x78,0x30,0x30,0x30,0x30,0x00,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x3C,
+       0x60,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x00,
+       0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x38,0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00,
+       0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0xEC,0xFE,0xFE,0xFE,0xD6,0xC6,0x00,
+       0x00,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00,
+       0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x60,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x06,
+       0x00,0x7E,0x70,0x60,0x60,0x60,0x60,0x00,0x00,0x3C,0x60,0x3C,0x06,0x66,0x3C,0x00,
+       0x30,0x78,0x30,0x30,0x30,0x30,0x1C,0x00,0x00,0x66,0x66,0x66,0x66,0x6E,0x3E,0x00,
+       0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x7C,0x6C,0x00,
+       0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x06,0x3C,
+       0x00,0x7E,0x0C,0x18,0x30,0x60,0x7E,0x00,0x0E,0x18,0x0C,0x38,0x0C,0x18,0x0E,0x00,
+       0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x70,0x18,0x30,0x1C,0x30,0x18,0x70,0x00,
+       0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x10,0x28,0x10,0x54,0xAA,0x44,0x00,0x00,
+};
+
+
+/* The font is generated from Xorg clR5x8.bdf */
+/*
+COMMENT  Copyright 1989 Dale Schumacher, dal@syntel.mn.org
+COMMENT                 399 Beacon Ave.
+COMMENT                 St. Paul, MN  55104-3527
+COMMENT
+COMMENT  Permission to use, copy, modify, and distribute this software and
+COMMENT  its documentation for any purpose and without fee is hereby
+COMMENT  granted, provided that the above copyright notice appear in all
+COMMENT  copies and that both that copyright notice and this permission
+COMMENT  notice appear in supporting documentation, and that the name of
+COMMENT  Dale Schumacher not be used in advertising or publicity pertaining to
+COMMENT  distribution of the software without specific, written prior
+COMMENT  permission.  Dale Schumacher makes no representations about the
+COMMENT  suitability of this software for any purpose.  It is provided "as
+COMMENT  is" without express or implied warranty.
+COMMENT
+*/
+unsigned char fontdata6x8[256][8] = {
+{ 0x7c>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0xff>>2, 0x7c>>2, },
+{ 0x00>>2, 0x00>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x40>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x4c>>2, 0x44>>2, 0x3c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x1c>>2, 0x04>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x48>>2, 0x50>>2, 0x60>>2, 0x50>>2, 0x48>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x6c>>2, 0x54>>2, 0x54>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x64>>2, 0x54>>2, 0x4c>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x0c>>2, },
+{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x78>>2, 0x50>>2, 0x4c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x38>>2, 0x04>>2, 0x78>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x28>>2, 0x28>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x54>>2, 0x54>>2, 0x6c>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x7c>>2, 0x00>>2, },
+{ 0xe0>>2, 0x80>>2, 0xe0>>2, 0x8c>>2, 0xf0>>2, 0x10>>2, 0x10>>2, 0x0c>>2, },
+{ 0x00>>2, 0x10>>2, 0x38>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x7c>>2, 0x38>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x18>>2, 0xfc>>2, 0x18>>2, 0x10>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x20>>2, 0x60>>2, 0xfc>>2, 0x60>>2, 0x20>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x10>>2, 0x00>>2, },
+{ 0x28>>2, 0x28>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x28>>2, 0x7c>>2, 0x28>>2, 0x7c>>2, 0x28>>2, 0x00>>2, 0x00>>2, },
+{ 0x10>>2, 0x3c>>2, 0x50>>2, 0x38>>2, 0x14>>2, 0x78>>2, 0x10>>2, 0x00>>2, },
+{ 0x60>>2, 0x64>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x4c>>2, 0x0c>>2, 0x00>>2, },
+{ 0x38>>2, 0x40>>2, 0x40>>2, 0x20>>2, 0x54>>2, 0x48>>2, 0x34>>2, 0x00>>2, },
+{ 0x10>>2, 0x20>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x04>>2, 0x08>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x08>>2, 0x04>>2, 0x00>>2, },
+{ 0x40>>2, 0x20>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x20>>2, 0x40>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x54>>2, 0x38>>2, 0x54>>2, 0x10>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x10>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x20>>2, },
+{ 0x00>>2, 0x00>>2, 0x00>>2, 0x7c>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x04>>2, 0x04>>2, 0x08>>2, 0x08>>2, 0x10>>2, 0x10>>2, 0x20>>2, 0x20>>2, },
+{ 0x38>>2, 0x44>>2, 0x4c>>2, 0x54>>2, 0x64>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x10>>2, 0x30>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x04>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x7c>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x04>>2, 0x18>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x18>>2, 0x18>>2, 0x28>>2, 0x28>>2, 0x7c>>2, 0x08>>2, 0x1c>>2, 0x00>>2, },
+{ 0x7c>>2, 0x40>>2, 0x78>>2, 0x04>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x18>>2, 0x20>>2, 0x40>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x7c>>2, 0x44>>2, 0x04>>2, 0x08>>2, 0x08>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, 0x08>>2, 0x30>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x10>>2, 0x00>>2, 0x00>>2, 0x10>>2, 0x10>>2, 0x20>>2, },
+{ 0x00>>2, 0x0c>>2, 0x30>>2, 0xc0>>2, 0x30>>2, 0x0c>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x00>>2, 0x7c>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0xc0>>2, 0x30>>2, 0x0c>>2, 0x30>>2, 0xc0>>2, 0x00>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x04>>2, 0x08>>2, 0x10>>2, 0x00>>2, 0x10>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x5c>>2, 0x5c>>2, 0x58>>2, 0x40>>2, 0x38>>2, 0x00>>2, },
+{ 0x10>>2, 0x28>>2, 0x44>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x70>>2, 0x48>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x48>>2, 0x70>>2, 0x00>>2, },
+{ 0x7c>>2, 0x40>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
+{ 0x7c>>2, 0x40>>2, 0x40>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x40>>2, 0x4c>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x44>>2, 0x7c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x7c>>2, 0x00>>2, },
+{ 0x1c>>2, 0x04>>2, 0x04>>2, 0x04>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x44>>2, 0x48>>2, 0x50>>2, 0x60>>2, 0x50>>2, 0x48>>2, 0x44>>2, 0x00>>2, },
+{ 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
+{ 0x44>>2, 0x6c>>2, 0x54>>2, 0x54>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x44>>2, 0x64>>2, 0x64>>2, 0x54>>2, 0x4c>>2, 0x4c>>2, 0x44>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x0c>>2, },
+{ 0x78>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x50>>2, 0x48>>2, 0x44>>2, 0x00>>2, },
+{ 0x38>>2, 0x44>>2, 0x40>>2, 0x38>>2, 0x04>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x44>>2, 0x28>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x44>>2, 0x54>>2, 0x54>>2, 0x6c>>2, 0x44>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x44>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x7c>>2, 0x04>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x40>>2, 0x7c>>2, 0x00>>2, },
+{ 0x1c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x1c>>2, 0x00>>2, },
+{ 0x20>>2, 0x20>>2, 0x10>>2, 0x10>>2, 0x08>>2, 0x08>>2, 0x04>>2, 0x04>>2, },
+{ 0x70>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x70>>2, 0x00>>2, },
+{ 0x10>>2, 0x28>>2, 0x44>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0xfc>>2, 0x00>>2, },
+{ 0x10>>2, 0x08>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x4c>>2, 0x34>>2, 0x00>>2, },
+{ 0x40>>2, 0x40>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x3c>>2, 0x00>>2, },
+{ 0x04>>2, 0x04>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x7c>>2, 0x40>>2, 0x38>>2, 0x00>>2, },
+{ 0x1c>>2, 0x20>>2, 0x78>>2, 0x20>>2, 0x20>>2, 0x20>>2, 0x20>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, 0x38>>2, },
+{ 0x40>>2, 0x40>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x10>>2, 0x00>>2, 0x30>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x38>>2, 0x00>>2, },
+{ 0x08>>2, 0x00>>2, 0x38>>2, 0x08>>2, 0x08>>2, 0x08>>2, 0x08>>2, 0x70>>2, },
+{ 0x40>>2, 0x40>>2, 0x48>>2, 0x50>>2, 0x60>>2, 0x50>>2, 0x48>>2, 0x00>>2, },
+{ 0x30>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x68>>2, 0x54>>2, 0x54>>2, 0x54>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x58>>2, 0x64>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x38>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x38>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x78>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x78>>2, 0x40>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, },
+{ 0x00>>2, 0x00>>2, 0x58>>2, 0x60>>2, 0x40>>2, 0x40>>2, 0x40>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x3c>>2, 0x40>>2, 0x38>>2, 0x04>>2, 0x78>>2, 0x00>>2, },
+{ 0x10>>2, 0x10>>2, 0x7c>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x0c>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x4c>>2, 0x34>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x6c>>2, 0x28>>2, 0x28>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x54>>2, 0x54>>2, 0x54>>2, 0x28>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x28>>2, 0x10>>2, 0x28>>2, 0x44>>2, 0x00>>2, },
+{ 0x00>>2, 0x00>>2, 0x44>>2, 0x44>>2, 0x44>>2, 0x3c>>2, 0x04>>2, 0x38>>2, },
+{ 0x00>>2, 0x00>>2, 0x7c>>2, 0x08>>2, 0x10>>2, 0x20>>2, 0x7c>>2, 0x00>>2, },
+{ 0x04>>2, 0x08>>2, 0x08>>2, 0x10>>2, 0x08>>2, 0x08>>2, 0x04>>2, 0x00>>2, },
+{ 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x10>>2, 0x00>>2, },
+{ 0x40>>2, 0x20>>2, 0x20>>2, 0x10>>2, 0x20>>2, 0x20>>2, 0x40>>2, 0x00>>2, },
+{ 0x20>>2, 0x54>>2, 0x08>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, 0x00>>2, },
+{ 0x00>>2, 0x10>>2, 0x10>>2, 0x28>>2, 0x28>>2, 0x44>>2, 0x7c>>2, 0x00>>2, },
+};
+
diff --git a/drivers/gp2x/fonts.h b/drivers/gp2x/fonts.h
new file mode 100644 (file)
index 0000000..dbbdd4c
--- /dev/null
@@ -0,0 +1,4 @@
+
+extern unsigned char fontdata8x8[64*16];
+extern unsigned char fontdata6x8[256-32][8];
+
index 30934bc..20af608 100644 (file)
  */
 
 #include <stdio.h>
  */
 
 #include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <linux/soundcard.h>
 
 
+#include "../../driver.h"
 #include "gp2x.h"
 #include "minimal.h"
 #include "throttle.h"
 
 
 extern int soundvol;
 #include "gp2x.h"
 #include "minimal.h"
 #include "throttle.h"
 
 
 extern int soundvol;
-extern unsigned long gp2x_dev[8];
 
 
-// always have this call
-INLINE void gp2x_sound_frame(void *blah, void *buff, int samples)
-{
-}
 
 void WriteSound(int16 *Buffer, int Count)
 {
 
 void WriteSound(int16 *Buffer, int Count)
 {
-       write(gp2x_dev[3], Buffer, Count<<1);
+       gp2x_sound_write(Buffer, Count<<1);
        SpeedThrottle();
 }
 
        SpeedThrottle();
 }
 
-void* gp2x_write_sound(void* blah)
-{
-       return NULL;
-}
-
 void SilenceSound(int n)
 {
        soundvol=0;
 void SilenceSound(int n)
 {
        soundvol=0;
index 03d4abc..d74023a 100644 (file)
 
 #include "../../video.h"
 
 
 #include "../../video.h"
 
+#include "main.h"
 #include "gp2x.h"
 #include "minimal.h"
 #include "gp2x.h"
 #include "minimal.h"
+#include "fonts.h"
 
 extern int showfps;
 
 static char fps_str[32];
 static int framesEmulated, framesRendered;
 
 
 extern int showfps;
 
 static char fps_str[32];
 static int framesEmulated, framesRendered;
 
+int gp2x_palette[256];
+
 int scaled_display=0;
 int paletterefresh;
 
 #define FPS_COLOR 1
 
 
 int scaled_display=0;
 int paletterefresh;
 
 #define FPS_COLOR 1
 
 
-static unsigned char fontdata8x8[] =
-{
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-       0x3C,0x42,0x99,0xBD,0xBD,0x99,0x42,0x3C,0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C,
-       0xFE,0x82,0x8A,0xD2,0xA2,0x82,0xFE,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00,
-       0x80,0xC0,0xF0,0xFC,0xF0,0xC0,0x80,0x00,0x01,0x03,0x0F,0x3F,0x0F,0x03,0x01,0x00,
-       0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0x00,0xEE,0xEE,0xEE,0xCC,0x00,0xCC,0xCC,0x00,
-       0x00,0x00,0x30,0x68,0x78,0x30,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00,
-       0x3C,0x66,0x7A,0x7A,0x7E,0x7E,0x3C,0x00,0x0E,0x3E,0x3A,0x22,0x26,0x6E,0xE4,0x40,
-       0x18,0x3C,0x7E,0x3C,0x3C,0x3C,0x3C,0x00,0x3C,0x3C,0x3C,0x3C,0x7E,0x3C,0x18,0x00,
-       0x08,0x7C,0x7E,0x7E,0x7C,0x08,0x00,0x00,0x10,0x3E,0x7E,0x7E,0x3E,0x10,0x00,0x00,
-       0x58,0x2A,0xDC,0xC8,0xDC,0x2A,0x58,0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00,
-       0x00,0x10,0x10,0x38,0x38,0x7C,0xFE,0x00,0xFE,0x7C,0x38,0x38,0x10,0x10,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x18,0x00,0x18,0x18,0x00,
-       0x6C,0x6C,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7C,0x28,0x7C,0x28,0x00,0x00,
-       0x10,0x38,0x60,0x38,0x0C,0x78,0x10,0x00,0x40,0xA4,0x48,0x10,0x24,0x4A,0x04,0x00,
-       0x18,0x34,0x18,0x3A,0x6C,0x66,0x3A,0x00,0x18,0x18,0x20,0x00,0x00,0x00,0x00,0x00,
-       0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x00,0x0C,0x06,0x06,0x06,0x06,0x06,0x0C,0x00,
-       0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00,
-       0x38,0x4C,0xC6,0xC6,0xC6,0x64,0x38,0x00,0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00,
-       0x7C,0xC6,0x0E,0x3C,0x78,0xE0,0xFE,0x00,0x7E,0x0C,0x18,0x3C,0x06,0xC6,0x7C,0x00,
-       0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x00,0xFC,0xC0,0xFC,0x06,0x06,0xC6,0x7C,0x00,
-       0x3C,0x60,0xC0,0xFC,0xC6,0xC6,0x7C,0x00,0xFE,0xC6,0x0C,0x18,0x30,0x30,0x30,0x00,
-       0x78,0xC4,0xE4,0x78,0x86,0x86,0x7C,0x00,0x7C,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00,
-       0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30,
-       0x1C,0x38,0x70,0xE0,0x70,0x38,0x1C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,
-       0x70,0x38,0x1C,0x0E,0x1C,0x38,0x70,0x00,0x7C,0xC6,0xC6,0x1C,0x18,0x00,0x18,0x00,
-       0x3C,0x42,0x99,0xA1,0xA5,0x99,0x42,0x3C,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00,
-       0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00,0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,
-       0xF8,0xCC,0xC6,0xC6,0xC6,0xCC,0xF8,0x00,0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xFE,0x00,
-       0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xC0,0x00,0x3E,0x60,0xC0,0xCE,0xC6,0x66,0x3E,0x00,
-       0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,
-       0x06,0x06,0x06,0x06,0xC6,0xC6,0x7C,0x00,0xC6,0xCC,0xD8,0xF0,0xF8,0xDC,0xCE,0x00,
-       0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00,
-       0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
-       0xFC,0xC6,0xC6,0xC6,0xFC,0xC0,0xC0,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x7A,0x00,
-       0xFC,0xC6,0xC6,0xCE,0xF8,0xDC,0xCE,0x00,0x78,0xCC,0xC0,0x7C,0x06,0xC6,0x7C,0x00,
-       0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
-       0xC6,0xC6,0xC6,0xEE,0x7C,0x38,0x10,0x00,0xC6,0xC6,0xD6,0xFE,0xFE,0xEE,0xC6,0x00,
-       0xC6,0xEE,0x3C,0x38,0x7C,0xEE,0xC6,0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00,
-       0xFE,0x0E,0x1C,0x38,0x70,0xE0,0xFE,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,
-       0x60,0x60,0x30,0x18,0x0C,0x06,0x06,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,
-       0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
-       0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0x66,0x3C,0x00,
-       0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x00,
-       0x06,0x3E,0x66,0x66,0x66,0x66,0x3E,0x00,0x00,0x3C,0x66,0x66,0x7E,0x60,0x3C,0x00,
-       0x1C,0x30,0x78,0x30,0x30,0x30,0x30,0x00,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x3C,
-       0x60,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x00,
-       0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x38,0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00,
-       0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0xEC,0xFE,0xFE,0xFE,0xD6,0xC6,0x00,
-       0x00,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00,
-       0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x60,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x06,
-       0x00,0x7E,0x70,0x60,0x60,0x60,0x60,0x00,0x00,0x3C,0x60,0x3C,0x06,0x66,0x3C,0x00,
-       0x30,0x78,0x30,0x30,0x30,0x30,0x1C,0x00,0x00,0x66,0x66,0x66,0x66,0x6E,0x3E,0x00,
-       0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x7C,0x6C,0x00,
-       0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x06,0x3C,
-       0x00,0x7E,0x0C,0x18,0x30,0x60,0x7E,0x00,0x0E,0x18,0x0C,0x38,0x0C,0x18,0x0E,0x00,
-       0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x70,0x18,0x30,0x1C,0x30,0x18,0x70,0x00,
-       0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x10,0x28,0x10,0x54,0xAA,0x44,0x00,0x00,
-};
-
 static void gp2x_text(unsigned char *screen, int x, int y, char *text, int color, int flip)
 {
        int i,l,slen;
 static void gp2x_text(unsigned char *screen, int x, int y, char *text, int color, int flip)
 {
        int i,l,slen;
@@ -135,10 +71,10 @@ void CleanSurface(void)
        int c=4;
        while (c--)
        {
        int c=4;
        while (c--)
        {
-               memset (gp2x_screen8, 0, 320*240);
+               memset(gp2x_screen, 0, 320*240);
                gp2x_video_flip();
        }
                gp2x_video_flip();
        }
-       XBuf = gp2x_screen8;
+       XBuf = gp2x_screen;
 }
 
 
 }
 
 
@@ -157,7 +93,7 @@ int InitVideo(void)
 
        srendline=0;
        erendline=239;
 
        srendline=0;
        erendline=239;
-       XBuf = gp2x_screen8;
+       XBuf = gp2x_screen;
        return 1;
 }
 
        return 1;
 }
 
@@ -169,8 +105,8 @@ void ToggleFS(void)
 
 void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b)
 {
 
 void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b)
 {
-       gp2x_video_color8(index, r, g, b);
-       gp2x_video_setpalette();
+       gp2x_palette[index] = (r << 16) | (g << 8) | b;
+       gp2x_video_setpalette(gp2x_palette, index + 1);
 
        paletterefresh = 1;
 }
 
        paletterefresh = 1;
 }
@@ -178,9 +114,10 @@ void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b)
 
 void FCEUD_GetPalette(uint8 index, uint8 * r, uint8 * g, uint8 * b)
 {
 
 void FCEUD_GetPalette(uint8 index, uint8 * r, uint8 * g, uint8 * b)
 {
-       *r = (uint8) gp2x_palette[(index << 1) + 1];
-       *g = (uint8) (gp2x_palette[(index << 1) + 0] >> 8);
-       *b = (uint8) gp2x_palette[(index << 1) + 0];
+       int pix = gp2x_palette[index];
+       *r = (uint8) (pix >> 16);
+       *g = (uint8) (pix >> 8);
+       *b = (uint8)  pix;
 }
 
 
 }
 
 
@@ -242,9 +179,9 @@ void BlitScreen(uint8 *buf)
 
        framesRendered++;
 
 
        framesRendered++;
 
-       printFps(gp2x_screen8);
+       printFps(gp2x_screen);
        gp2x_video_flip();
        gp2x_video_flip();
-       XBuf = gp2x_screen8;
+       XBuf = gp2x_screen;
 }
 
 
 }
 
 
index fc70dd1..e7c3a0e 100644 (file)
@@ -2,98 +2,72 @@
 #include <stdlib.h>
 #include <string.h>
 
 #include <stdlib.h>
 #include <string.h>
 
+#include "../../driver.h"
+#include "../common/config.h"
+#include "../common/args.h"
 #include "gp2x.h"
 #include "gp2x-video.h"
 #ifdef NETWORK
 #include "unix-netplay.h"
 #endif
 #include "gp2x.h"
 #include "gp2x-video.h"
 #ifdef NETWORK
 #include "unix-netplay.h"
 #endif
+
 #include "minimal.h"
 #include "minimal.h"
+#include "cpuctrl.h"
+#include "squidgehack.h"
 
 int CLImain(int argc, char *argv[]);
 
 int CLImain(int argc, char *argv[]);
-extern void SetVideoScaling(int, int, int);
 
 //#define SOUND_RATE 44100
 #define SOUND_RATE 22050
 
 //#define SOUND_RATE 44100
 #define SOUND_RATE 22050
-#define GP2X_PORT_VERSION "0.3"
+#define GP2X_PORT_VERSION "0.4"
 
 DSETTINGS Settings;
 CFGSTRUCT DriverConfig[]={
 
 DSETTINGS Settings;
 CFGSTRUCT DriverConfig[]={
-       AC(_xscale),
-       AC(_yscale),
-       AC(_xscalefs),
-       AC(_yscalefs),
-       AC(_efx),
-       AC(_efxfs),
-        AC(_sound),
-       #ifdef DSPSOUND
-        AC(_f8bit),
-       #else
-       AC(_ebufsize),
-       AC(_lbufsize),
-       #endif
-       AC(_fullscreen),
-        AC(_xres),
-       AC(_yres),
-        ACA(joyBMap),
-       ACA(joyAMap),
-        ACA(joy),
-        //ACS(_fshack),
+        AC(Settings.sound),
+        ACA(Settings.joyBMap),
+       ACA(Settings.joyAMap),
+        ACA(Settings.joy),
+       AC(Settings.showfps),
+       AC(Settings.scaling),
+       AC(Settings.frameskip),
+       AC(Settings.sstate_confirm),
+       AC(Settings.region_force),
+       AC(Settings.cpuclock),
+       AC(Settings.mmuhack),
+       AC(Settings.ramtimings),
+       // TODO
         ENDCFGSTRUCT
 };
 
         ENDCFGSTRUCT
 };
 
-//-fshack x       Set the environment variable SDL_VIDEODRIVER to \"x\" when
-//                entering full screen mode and x is not \"0\".
 
 char *DriverUsage=
 
 char *DriverUsage=
-"-xres   x       Set horizontal resolution to x for full screen mode.\n\
--yres   x       Set vertical resolution to x for full screen mode.\n\
--xscale(fs) x  Multiply width by x.\n\
--yscale(fs) x  Multiply height by x.\n\
--efx(fs) x     Enable scanlines effect if x is non zero.  yscale must be >=2\n\
-               and preferably a multiple of 2.\n\
--fs     x      Select full screen mode if x is non zero.\n\
--joyx   y       Use joystick y as virtual joystick x.\n\
+"-joyx   y       Use joystick y as virtual joystick x.\n\
 -sound x        Sound.\n\
                  0 = Disabled.\n\
                  Otherwise, x = playback rate.\n\
 -sound x        Sound.\n\
                  0 = Disabled.\n\
                  Otherwise, x = playback rate.\n\
+-showfps x      Display fps counter if x is nonzero\n\
+-mmuhack x      Enable squidge's MMU hack if x is nonzero (GP2X).\n\
+-ramtimings x   Enable RAM overclocking if x is nonzero (GP2X).\n\
 "
 "
-#ifdef DSPSOUND
-"-f8bit x        Force 8-bit sound.\n\
-                 0 = Disabled.\n\
-                 1 = Enabled.\n\
-"
-#else
-"-lbufsize x   Internal FCE Ultra sound buffer size. Size = 2^x samples.\n\
--ebufsize x    External SDL sound buffer size. Size = 2^x samples.\n\
-"
-#endif
+#ifdef NETWORK
 "-connect s      Connect to server 's' for TCP/IP network play.\n\
 -server         Be a host/server for TCP/IP network play.\n\
 "-connect s      Connect to server 's' for TCP/IP network play.\n\
 -server         Be a host/server for TCP/IP network play.\n\
--netport x      Use TCP/IP port x for network play.";
+-netport x      Use TCP/IP port x for network play."
+#endif
+;
 
 #ifdef NETWORK
 static int docheckie[2]={0,0};
 #endif
 ARGPSTRUCT DriverArgs[]={
 
 #ifdef NETWORK
 static int docheckie[2]={0,0};
 #endif
 ARGPSTRUCT DriverArgs[]={
-         {"-joy1",0,&joy[0],0},{"-joy2",0,&joy[1],0},
-         {"-joy3",0,&joy[2],0},{"-joy4",0,&joy[3],0},
-        {"-xscale",0,&_xscale,0},
-        {"-yscale",0,&_yscale,0},
-        {"-efx",0,&_efx,0},
-         {"-xscalefs",0,&_xscalefs,0},
-         {"-yscalefs",0,&_yscalefs,0},
-         {"-efxfs",0,&_efxfs,0},
-        {"-xres",0,&_xres,0},
-         {"-yres",0,&_yres,0},
-         {"-fs",0,&_fullscreen,0},
-         //{"-fshack",0,&_fshack,0x4001},
-         {"-sound",0,&_sound,0},
-        #ifdef DSPSOUND
-         {"-f8bit",0,&_f8bit,0},
-        #else
-        {"-lbufsize",0,&_lbufsize,0},
-        {"-ebufsize",0,&_ebufsize,0},
-        #endif
+         {"-joy1",0,&Settings.joy[0],0},{"-joy2",0,&Settings.joy[1],0},
+         {"-joy3",0,&Settings.joy[2],0},{"-joy4",0,&Settings.joy[3],0},
+         {"-sound",0,&Settings.sound,0},
+         {"-showfps",0,&Settings.showfps,0},
+         {"-mmuhack",0,&Settings.mmuhack,0},
+         {"-ramtimings",0,&Settings.ramtimings,0},
+         {"-menu",0,&ext_menu,0x4001},
+         {"-menustate",0,&ext_state,0x4001},
         #ifdef NETWORK
          {"-connect",&docheckie[0],&netplayhost,0x4001},
          {"-server",&docheckie[1],0,0},
         #ifdef NETWORK
          {"-connect",&docheckie[0],&netplayhost,0x4001},
          {"-server",&docheckie[1],0,0},
@@ -104,56 +78,24 @@ ARGPSTRUCT DriverArgs[]={
 
 
 
 
 
 
-
-
 void GetBaseDirectory(char *BaseDirectory)
 {
 void GetBaseDirectory(char *BaseDirectory)
 {
- char *ol;
-
- ol="/mnt/sd/roms/nes";
- BaseDirectory[0]=0;
- if(ol)
- {
-  strncpy(BaseDirectory,ol,2047);
-  BaseDirectory[2047]=0;
-  strcat(BaseDirectory,"/fceultra");
- }
+ strcpy(BaseDirectory, "fceultra");
 }
 
 static void SetDefaults(void)
 {
 }
 
 static void SetDefaults(void)
 {
- _xres=320;
- _yres=240;
- _fullscreen=0;
- _sound=SOUND_RATE; // 48000 wrong
- #ifdef DSPSOUND
- _f8bit=0;
- #else
- _lbufsize=10;
- _ebufsize=8;
- #endif
- _xscale=_yscale=_xscalefs=_yscalefs=1;
- _efx=_efxfs=0;
- //_fshack=_fshacksave=0;
- memset(joy,0,sizeof(joy));
+ memset(&Settings,0,sizeof(Settings));
+ Settings.cpuclock = 150;
+ Settings.frameskip = -1; // auto
+ Settings.mmuhack = 1;
+ Settings.sound=SOUND_RATE;
 }
 
 void DoDriverArgs(void)
 {
         int x;
 
 }
 
 void DoDriverArgs(void)
 {
         int x;
 
-       #ifdef BROKEN
-        if(_fshack)
-        {
-         if(_fshack[0]=='0')
-          if(_fshack[1]==0)
-          {
-           free(_fshack);
-           _fshack=0;
-          }
-        }
-       #endif
-
        #ifdef NETWORK
         if(docheckie[0])
          netplay=2;
        #ifdef NETWORK
         if(docheckie[0])
          netplay=2;
@@ -165,17 +107,20 @@ void DoDriverArgs(void)
        #endif
 
         for(x=0;x<4;x++)
        #endif
 
         for(x=0;x<4;x++)
-         if(!joy[x])
+         if(!Settings.joy[x])
         {
         {
-         memset(joyBMap[x],0,sizeof(joyBMap[0]));
-         memset(joyAMap[x],0,sizeof(joyAMap[0]));
+         memset(Settings.joyBMap[x],0,sizeof(Settings.joyBMap[0]));
+         memset(Settings.joyAMap[x],0,sizeof(Settings.joyAMap[0]));
         }
 }
         }
 }
+
 int InitMouse(void)
 {
  return(0);
 }
 int InitMouse(void)
 {
  return(0);
 }
+
 void KillMouse(void){}
 void KillMouse(void){}
+
 void GetMouseData(uint32 *d)
 {
 }
 void GetMouseData(uint32 *d)
 {
 }
@@ -200,13 +145,14 @@ char *GetKeyboard(void)
  return NULL;
 }
 
  return NULL;
 }
 
-#include "unix-basedir.h"
-extern int showfps;
-extern int swapbuttons;
+extern int swapbuttons; // TODO: rm
 char **g_argv;
 
 char **g_argv;
 
+
+// TODO: cleanup
 int main(int argc, char *argv[])
 {
 int main(int argc, char *argv[])
 {
+       int ret;
        g_argv = argv;
 
         puts("Starting GPFCE - Port version " GP2X_PORT_VERSION " (" __DATE__ ")");
        g_argv = argv;
 
         puts("Starting GPFCE - Port version " GP2X_PORT_VERSION " (" __DATE__ ")");
@@ -214,42 +160,42 @@ int main(int argc, char *argv[])
         puts("Ported by Zheng Zhu");
         puts("Additional optimization/misc work by notaz\n");
 
         puts("Ported by Zheng Zhu");
         puts("Additional optimization/misc work by notaz\n");
 
-         //  stereo
-        //gp2x_init (1000, 8, SOUND_RATE, 16, 1, 60);
-
-        // mono 44khz
-       //gp2x_init (1000, 8, SOUND_RATE<<1, 16, 0, 60);
-        // mono 22khz
-       gp2x_init (1000, 8, SOUND_RATE, 16, 0, 60);
+       gp2x_init();
+       cpuctrl_init();
 
         // unscale the screen, in case this is bad.
 
         // unscale the screen, in case this is bad.
-        SetVideoScaling(320, 320, 240);
+       gp2x_video_changemode(8);
+        gp2x_video_RGB_setscaling(0, 320, 240);
 
         SetDefaults();
 
         SetDefaults();
-        int ret=CLImain(argc,argv);
+
+        ret = CLImain(argc,argv);
 
         // unscale the screen, in case this is bad.
 
         // unscale the screen, in case this is bad.
-        SetVideoScaling(320, 320, 240);
+        gp2x_video_RGB_setscaling(0, 320, 240);
 
 
+       cpuctrl_deinit();
         gp2x_deinit();
         gp2x_deinit();
-        // make sure sound thread has exited cleanly
-        printf("Exiting main().  terminated");
-        if (showfps && swapbuttons)
-        {
-          execl("./selector","./selector","./gpfce_showfps_swapbuttons_config",NULL);
-        }
-        else if (showfps)
-        {
-          execl("./selector","./selector","./gpfce_showfps_config",NULL);
-        }
-        else if (swapbuttons)
-        {
-          execl("./selector","./selector","./gpfce_swapbuttons_config",NULL);
-        }
-        else
-        {
-          execl("./selector","./selector","./gpfce_config",NULL);
-        }
+
         return(ret?0:-1);
 }
 
         return(ret?0:-1);
 }
 
+
+int mmuhack_status = 0;
+
+/* optional GP2X stuff to be done after config is loaded */
+void gp2x_opt_setup(void)
+{
+       if (Settings.mmuhack) {
+               int ret = mmuhack();
+               printf("squidge hack code finished and returned %i\n", ret); fflush(stdout);
+               mmuhack_status = ret;
+       }
+       if (Settings.ramtimings) {
+               printf("setting RAM timings.. "); fflush(stdout);
+               // craigix: --trc 6 --tras 4 --twr 1 --tmrd 1 --trfc 1 --trp 2 --trcd 2
+               set_RAM_Timings(6, 4, 1, 1, 1, 2, 2);
+               printf("done.\n"); fflush(stdout);
+       }
+}
+
index 7882e5b..799e0cb 100644 (file)
@@ -1,46 +1,20 @@
-#include "../../driver.h"
-#include "../common/args.h"
-#include "../common/config.h"
-#include "main.h"
-
 typedef struct {
 typedef struct {
-        int xres;
-        int yres;
-       int xscale,yscale;
-       int xscalefs,yscalefs;
-       int efx,efxfs;
-        int fullscreen;
        int sound;
        int sound;
-       #ifdef DSPSOUND
-       int f8bit;
-       #else
-       int lbufsize,ebufsize;
-       #endif
        int joy[4];
        int joyAMap[4][2];
        int joyBMap[4][4];
        int joy[4];
        int joyAMap[4][2];
        int joyBMap[4][4];
-       char *fshack;
-       char *fshacksave;
+       // gp2x specific
+       int showfps;
+       int scaling;            // unscaled=0, hw_hor, hw_hor_vert, sw_hor
+       int frameskip;          // -1 ~ auto, >=0 ~ count
+       int sstate_confirm;
+       int region_force;       // 0 ~ off, 1 ~ PAL, 2 ~ NTSC
+       int cpuclock;
+       int mmuhack;
+       int ramtimings;
 } DSETTINGS;
 
 extern DSETTINGS Settings;
 
 } DSETTINGS;
 
 extern DSETTINGS Settings;
 
-#define _xres Settings.xres
-#define _yres Settings.yres
-#define _fullscreen Settings.fullscreen
-#define _sound Settings.sound
-#define _f8bit Settings.f8bit
-#define _xscale Settings.xscale
-#define _yscale Settings.yscale
-#define _xscalefs Settings.xscalefs
-#define _yscalefs Settings.yscalefs
-#define _efx Settings.efx
-#define _efxfs Settings.efxfs
-#define _ebufsize Settings.ebufsize
-#define _lbufsize Settings.lbufsize
-#define _fshack Settings.fshack
-#define _fshacksave Settings.fshacksave
+void gp2x_opt_setup(void);
 
 
-#define joyAMap Settings.joyAMap
-#define joyBMap Settings.joyBMap
-#define joy    Settings.joy
index 9ba438a..cd25e97 100644 (file)
 
 #include "minimal.h"
 
 
 #include "minimal.h"
 
+extern uint8 Exit; // exit emu loop
 
 extern int swapbuttons;
 extern int scaled_display;
 extern int FSkip_setting;
 
 
 extern int swapbuttons;
 extern int scaled_display;
 extern int FSkip_setting;
 
-extern void SetVideoScaling(int pixels,int width,int height);
-
 
 
 /* UsrInputType[] is user-specified.  InputType[] is current
 
 
 /* UsrInputType[] is user-specified.  InputType[] is current
@@ -99,7 +98,7 @@ static void setsoundvol(int soundvolume)
 void FCEUD_UpdateInput(void)
 {
   long lastpad2=lastpad;
 void FCEUD_UpdateInput(void)
 {
   long lastpad2=lastpad;
-  unsigned long pad=gp2x_joystick_read();
+  unsigned long pad=gp2x_joystick_read(1); // TODO: USB joys and stuff
   uint32 JS=0;
 
 #define down(b) (pad & GP2X_##b)
   uint32 JS=0;
 
 #define down(b) (pad & GP2X_##b)
@@ -132,6 +131,10 @@ void FCEUD_UpdateInput(void)
     //FCEUI_SetSoundVolume(soundvol);
     setsoundvol(soundvol);
   }
     //FCEUI_SetSoundVolume(soundvol);
     setsoundvol(soundvol);
   }
+  else if (down(VOL_DOWN) && down(VOL_UP))
+  {
+    Exit = 1;
+  }
 
   if (shift)
   {
 
   if (shift)
   {
@@ -149,11 +152,11 @@ void FCEUD_UpdateInput(void)
 
         if (scaled_display)
        {
 
         if (scaled_display)
        {
-         SetVideoScaling(320, 256, 240);
+         gp2x_video_RGB_setscaling(0, 256, 240);
        }
         else
        {
        }
         else
        {
-          SetVideoScaling(320, 320, 240);
+          gp2x_video_RGB_setscaling(0, 320, 240);
        }
 
         goto no_pad;
        }
 
         goto no_pad;
index 4437dc6..e9223f2 100644 (file)
@@ -37,6 +37,8 @@
 
 #include "main.h"
 #include "throttle.h"
 
 #include "main.h"
 #include "throttle.h"
+#include "menu.h"
+#include "gp2x.h"
 
 #include "../common/config.h"
 #include "../common/args.h"
 
 #include "../common/config.h"
 #include "../common/args.h"
 #include "../../fce.h"
 #include "../../ines.h"
 
 #include "../../fce.h"
 #include "../../ines.h"
 
+// internals
+extern char lastLoadedGameName[2048];
+extern uint8 Exit; // exit emu loop flag
+void CloseGame(void);
+
+FCEUGI *fceugi = NULL;
 static int ntsccol=0,ntschue=-1,ntsctint=-1;
 int soundvol=70;
 int inited=0;
 static int ntsccol=0,ntschue=-1,ntsctint=-1;
 int soundvol=70;
 int inited=0;
@@ -56,9 +64,7 @@ int swapbuttons=0;
 int showfps=0;
 
 int srendlinev[2]={0,0};
 int showfps=0;
 
 int srendlinev[2]={0,0};
-//int srendlinev[2]={0,0};
 int erendlinev[2]={239,239};
 int erendlinev[2]={239,239};
-//int erendlinev[2]={231,239};
 int srendline,erendline;
 
 
 int srendline,erendline;
 
 
@@ -123,6 +129,7 @@ static CFGSTRUCT fceuconfig[]={
        AC(eoptions),
        ACA(srendlinev),
        ACA(erendlinev),
        AC(eoptions),
        ACA(srendlinev),
        ACA(erendlinev),
+       ACA(lastLoadedGameName),
        ADDCFGSTRUCT(DriverConfig),
        ENDCFGSTRUCT
 };
        ADDCFGSTRUCT(DriverConfig),
        ENDCFGSTRUCT
 };
@@ -193,7 +200,7 @@ static void CloseStuff(int signum)
         exit(1);
 }
 
         exit(1);
 }
 
-static void DoArgs(int argc, char *argv[])
+static int DoArgs(int argc, char *argv[])
 {
         static char *cortab[5]={"none","gamepad","zapper","powerpad","arkanoid"};
         static int cortabi[5]={SI_NONE,SI_GAMEPAD,
 {
         static char *cortab[5]={"none","gamepad","zapper","powerpad","arkanoid"};
         static int cortabi[5]={SI_NONE,SI_GAMEPAD,
@@ -202,7 +209,7 @@ static void DoArgs(int argc, char *argv[])
        static int fccortabi[5]={SIFC_NONE,SIFC_ARKANOID,SIFC_SHADOW,
                                 SIFC_4PLAYER,SIFC_FKB};
 
        static int fccortabi[5]={SIFC_NONE,SIFC_ARKANOID,SIFC_SHADOW,
                                 SIFC_4PLAYER,SIFC_FKB};
 
-       int x;
+       int x, ret;
        static char *inputa[2]={0,0};
        static char *fcexp=0;
        static int docheckie[4];
        static char *inputa[2]={0,0};
        static char *fcexp=0;
        static int docheckie[4];
@@ -232,7 +239,7 @@ static void DoArgs(int argc, char *argv[])
         };
 
         memset(docheckie,0,sizeof(docheckie));
         };
 
         memset(docheckie,0,sizeof(docheckie));
-       ParseArguments(argc, argv, FCEUArgs);
+       ret=ParseArguments(argc, argv, FCEUArgs);
        if(cpalette)
        {
         if(cpalette[0]=='0')
        if(cpalette)
        {
         if(cpalette[0]=='0')
@@ -299,62 +306,97 @@ static void DoArgs(int argc, char *argv[])
          }
         }
        }
          }
         }
        }
+       return ret;
 }
 
 #include "usage.h"
 
 int CLImain(int argc, char *argv[])
 {
 }
 
 #include "usage.h"
 
 int CLImain(int argc, char *argv[])
 {
-       FCEUGI *tmp;
-       int ret;
-
-        if(argc<=1)
+       int last_arg_parsed;
+        /* TODO if(argc<=1)
         {
          ShowUsage(argv[0]);
          return 1;
         {
          ShowUsage(argv[0]);
          return 1;
-        }
+        }*/
 
         if(!DriverInitialize())
         {
         return 1;
         }
 
 
         if(!DriverInitialize())
         {
         return 1;
         }
 
-       if(!(ret=FCEUI_Initialize()))
+       if(!FCEUI_Initialize())
          return(1);
         GetBaseDirectory(BaseDirectory);
        FCEUI_SetBaseDirectory(BaseDirectory);
          return(1);
         GetBaseDirectory(BaseDirectory);
        FCEUI_SetBaseDirectory(BaseDirectory);
+       lastLoadedGameName[0] = 0;
 
        CreateDirs();
         LoadConfig();
 
        CreateDirs();
         LoadConfig();
-        DoArgs(argc-2,&argv[1]);
+       gp2x_opt_setup();
+        last_arg_parsed=DoArgs(argc-1,&argv[1]);
        if(cpalette)
         LoadCPalette();
        if(InitSound())
         inited|=1;
 
        if(cpalette)
         LoadCPalette();
        if(InitSound())
         inited|=1;
 
-        if(!(tmp=FCEUI_LoadGame(argv[argc-1])))
-        {
-         ret=0;
-         goto dk;
-        }
-       ParseGI(tmp);
-       //RefreshThrottleFPS();
-       InitOtherInput();
-
-       // additional print for gpfce
+       if (argc > 1 && !last_arg_parsed)
        {
        {
-        int MapperNo;
-        iNES_HEADER *head = iNESGetHead();
-         MapperNo = (head->ROM_type>>4);
-         MapperNo|=(head->ROM_type2&0xF0);
-        FCEU_DispMessage("%s, Mapper: %d%s%s", PAL?"PAL":"NTSC", MapperNo, (head->ROM_type&2)?", BB":"", (head->ROM_type&4)?", T":"");
+        strncpy(lastLoadedGameName, argv[argc-1], sizeof(lastLoadedGameName));
+        lastLoadedGameName[sizeof(lastLoadedGameName)-1] = 0;
+        Exit = 0;
+       }
+       else
+       {
+        lastLoadedGameName[0] = 0;
+        Exit = 1;
        }
 
        }
 
-       FCEUI_Emulate();
+       while (1)
+       {
+        if(!Exit)
+        {
+         if (fceugi)
+          CloseGame();
+          fceugi=FCEUI_LoadGame(lastLoadedGameName);
+         if (fceugi)
+         {
+          ParseGI(fceugi);
+          //RefreshThrottleFPS();
+          InitOtherInput();
+
+          // additional print for gpfce
+          // TODO: handlers for other formats then iNES
+          {
+         int MapperNo;
+         iNES_HEADER *head = iNESGetHead();
+          MapperNo = (head->ROM_type>>4);
+          MapperNo|=(head->ROM_type2&0xF0);
+         FCEU_DispMessage("%s, Mapper: %d%s%s", PAL?"PAL":"NTSC", MapperNo, (head->ROM_type&2)?", BB":"", (head->ROM_type&4)?", T":"");
+          }
+         }
+         else
+          strcpy(menuErrorMsg, "failed to load ROM");
+        }
+         if(Exit || !fceugi)
+         {
+          int ret;
+         ret = gp2x_menu_do();
+         if (ret == 1) break;          // exit emu
+         if (ret == 2) {               // reload ROM
+          Exit = 0;
+          continue;
+         }
+         }
+
+        gp2x_video_changemode(Settings.scaling == 3 ? 15 : 8);
+         gp2x_video_RGB_setscaling(0, 320, 240);
+        gp2x_start_sound(22050, 16, 0);
+        FCEUI_Emulate();
+       }
 
 
-       dk:
        DriverKill();
        DriverKill();
-        return(ret?0:1);
+        return 0;
 }
 
 static int DriverInitialize(void)
 }
 
 static int DriverInitialize(void)
index 99dc5b5..b544bd6 100644 (file)
@@ -28,3 +28,5 @@ extern int eoptions;
 #define EO_NOTHROTTLE  64
 extern int srendline,erendline,srendlinev[2],erendlinev[2];
 extern int NoWaiting;
 #define EO_NOTHROTTLE  64
 extern int srendline,erendline,srendlinev[2],erendlinev[2];
 extern int NoWaiting;
+
+extern FCEUGI *fceugi;
diff --git a/drivers/gp2x/menu.c b/drivers/gp2x/menu.c
new file mode 100644 (file)
index 0000000..bafabf3
--- /dev/null
@@ -0,0 +1,1091 @@
+// (c) Copyright 2006,2007 notaz, All rights reserved.\r
+// Free for non-commercial use.\r
+\r
+// For commercial use, separate licencing terms must be obtained.\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <stdarg.h>\r
+#include <unistd.h>\r
+#include <dirent.h>\r
+\r
+#include "minimal.h"\r
+#include "usbjoy.h"\r
+#include "asmutils.h"\r
+#include "menu.h"\r
+#include "main.h"\r
+#include "fonts.h"\r
+#include "gp2x.h"\r
+\r
+#ifndef _DIRENT_HAVE_D_TYPE\r
+#error "need d_type for file browser\r
+#endif\r
+\r
+extern char lastLoadedGameName[PATH_MAX];\r
+extern int  mmuhack_status;\r
+//extern int  state_slot; // TODO\r
+extern uint8 Exit; // exit emu loop flag\r
+\r
+static char *gp2xKeyNames[] = {\r
+       "UP",    "01???",  "LEFT", "03???", "DOWN", "05???", "RIGHT",    "07???",\r
+       "START", "SELECT", "L",    "R",     "A",    "B",     "X",        "Y",\r
+       "10???", "11???",  "12???","13???", "14???","15???", "VOL DOWN", "VOL UP",\r
+       "18???", "19???",  "1a???","PUSH",  "1c???","1d???", "1e???",    "1f???"\r
+};\r
+\r
+char menuErrorMsg[40] = {0, };\r
+\r
+// TODO\r
+void gp2x_fceu_copy_bg(void)\r
+{\r
+       memset(gp2x_screen, 0, 320*240*2);\r
+}\r
+\r
+// draws white text to current bbp15 screen\r
+static void gp2x_text_out15_(int x, int y, const char *text)\r
+{\r
+       int i,l;\r
+       unsigned short *screen = gp2x_screen;\r
+\r
+       screen = screen + x + y*320;\r
+\r
+       for (i = 0; i < strlen(text); i++)\r
+       {\r
+               for (l=0;l<8;l++)\r
+               {\r
+                       if(fontdata8x8[((text[i])*8)+l]&0x80) screen[l*320+0]=0xffff;\r
+                       if(fontdata8x8[((text[i])*8)+l]&0x40) screen[l*320+1]=0xffff;\r
+                       if(fontdata8x8[((text[i])*8)+l]&0x20) screen[l*320+2]=0xffff;\r
+                       if(fontdata8x8[((text[i])*8)+l]&0x10) screen[l*320+3]=0xffff;\r
+                       if(fontdata8x8[((text[i])*8)+l]&0x08) screen[l*320+4]=0xffff;\r
+                       if(fontdata8x8[((text[i])*8)+l]&0x04) screen[l*320+5]=0xffff;\r
+                       if(fontdata8x8[((text[i])*8)+l]&0x02) screen[l*320+6]=0xffff;\r
+                       if(fontdata8x8[((text[i])*8)+l]&0x01) screen[l*320+7]=0xffff;\r
+               }\r
+               screen += 8;\r
+       }\r
+}\r
+\r
+void gp2x_text_out15(int x, int y, const char *texto, ...)\r
+{\r
+       va_list args;\r
+       char    buffer[512];\r
+\r
+       va_start(args,texto);\r
+       vsprintf(buffer,texto,args);\r
+       va_end(args);\r
+\r
+       gp2x_text_out15_(x,y,buffer);\r
+}\r
+\r
+\r
+void gp2x_text_out15_lim(int x, int y, const char *texto, int max)\r
+{\r
+       char    buffer[320/8+1];\r
+\r
+       strncpy(buffer, texto, 320/8);\r
+       if (max > 320/8) max = 320/8;\r
+       if (max < 0) max = 0;\r
+       buffer[max] = 0;\r
+\r
+       gp2x_text_out15(x,y,buffer);\r
+}\r
+\r
+static void gp2x_smalltext16(int x, int y, const char *texto)\r
+{\r
+       int i;\r
+       unsigned char  *src;\r
+       unsigned short *dst;\r
+\r
+       for (i = 0;; i++, x += 6)\r
+       {\r
+               unsigned char c = (unsigned char) texto[i];\r
+               int h = 8;\r
+\r
+               if (!c) break;\r
+\r
+               src = fontdata6x8[c];\r
+               dst = (unsigned short *)gp2x_screen + x + y*320;\r
+\r
+               while (h--)\r
+               {\r
+                       int w = 0x20;\r
+                       while (w)\r
+                       {\r
+                               if( *src & w ) *dst = 0xffff;\r
+                               dst++;\r
+                               w>>=1;\r
+                       }\r
+                       src++;\r
+\r
+                       dst += 320-6;\r
+               }\r
+       }\r
+}\r
+\r
+static void gp2x_smalltext8_lim(int x, int y, const char *texto, int max)\r
+{\r
+       char    buffer[320/6+1];\r
+\r
+       strncpy(buffer, texto, 320/6);\r
+       if (max > 320/6) max = 320/6;\r
+       if (max < 0) max = 0;\r
+       buffer[max] = 0;\r
+\r
+       gp2x_smalltext16(x, y, buffer);\r
+}\r
+\r
+\r
+static unsigned long inp_prev = 0;\r
+static int inp_prevjoy = 0;\r
+\r
+static unsigned long wait_for_input(unsigned long interesting)\r
+{\r
+       unsigned long ret;\r
+       static int repeats = 0, wait = 50*1000;\r
+       int release = 0, i;\r
+\r
+       if (repeats == 2 || repeats == 4) wait /= 2;\r
+       if (repeats == 6) wait = 15 * 1000;\r
+\r
+       for (i = 0; i < 6 && inp_prev == gp2x_joystick_read(1); i++) {\r
+               if (i == 0) repeats++;\r
+               if (wait >= 30*1000) usleep(wait); // usleep sleeps for ~30ms minimum\r
+               else spend_cycles(wait * Settings.cpuclock);\r
+       }\r
+\r
+       while ( !((ret = gp2x_joystick_read(1)) & interesting) ) {\r
+               usleep(50000);\r
+               release = 1;\r
+       }\r
+\r
+       if (release || ret != inp_prev) {\r
+               repeats = 0;\r
+               wait = 50*1000;\r
+       }\r
+       inp_prev = ret;\r
+       inp_prevjoy = 0;\r
+\r
+       // we don't need diagonals in menus\r
+       if ((ret&GP2X_UP)   && (ret&GP2X_LEFT))  ret &= ~GP2X_LEFT;\r
+       if ((ret&GP2X_UP)   && (ret&GP2X_RIGHT)) ret &= ~GP2X_RIGHT;\r
+       if ((ret&GP2X_DOWN) && (ret&GP2X_LEFT))  ret &= ~GP2X_LEFT;\r
+       if ((ret&GP2X_DOWN) && (ret&GP2X_RIGHT)) ret &= ~GP2X_RIGHT;\r
+\r
+       return ret;\r
+}\r
+\r
+static unsigned long input2_read(unsigned long interesting, int *joy)\r
+{\r
+       unsigned long ret;\r
+       int i;\r
+\r
+       do\r
+       {\r
+               *joy = 0;\r
+               if ((ret = gp2x_joystick_read(0) & interesting)) break;\r
+               gp2x_usbjoy_update();\r
+               for (i = 0; i < num_of_joys; i++) {\r
+                       ret = gp2x_usbjoy_check2(i);\r
+                       if (ret) { *joy = i + 1; break; }\r
+               }\r
+               if (ret) break;\r
+       }\r
+       while(0);\r
+\r
+       return ret;\r
+}\r
+\r
+// similar to wait_for_input(), but returns joy num\r
+static unsigned long wait_for_input_usbjoy(unsigned long interesting, int *joy)\r
+{\r
+       unsigned long ret;\r
+       const int wait = 300*1000;\r
+       int i;\r
+\r
+       if (inp_prevjoy == 0) inp_prev &= interesting;\r
+       for (i = 0; i < 6; i++) {\r
+               ret = input2_read(interesting, joy);\r
+               if (*joy != inp_prevjoy || ret != inp_prev) break;\r
+               usleep(wait/6);\r
+       }\r
+\r
+       while ( !(ret = input2_read(interesting, joy)) ) {\r
+               usleep(50000);\r
+       }\r
+\r
+       inp_prev = ret;\r
+       inp_prevjoy = *joy;\r
+\r
+       return ret;\r
+}\r
+\r
+\r
+\r
+// -------------- ROM selector --------------\r
+\r
+static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel)\r
+{\r
+       int start, i, pos;\r
+\r
+       start = 12 - sel;\r
+       n--; // exclude current dir (".")\r
+\r
+       //memset(gp2x_screen, 0, 320*240);\r
+       gp2x_fceu_copy_bg();\r
+\r
+       if(start - 2 >= 0)\r
+               gp2x_smalltext8_lim(14, (start - 2)*10, curdir, 53-2);\r
+       for (i = 0; i < n; i++) {\r
+               pos = start + i;\r
+               if (pos < 0)  continue;\r
+               if (pos > 23) break;\r
+               if (namelist[i+1]->d_type == DT_DIR) {\r
+                       gp2x_smalltext8_lim(14,   pos*10, "/", 1);\r
+                       gp2x_smalltext8_lim(14+6, pos*10, namelist[i+1]->d_name, 53-3);\r
+               } else {\r
+                       gp2x_smalltext8_lim(14,   pos*10, namelist[i+1]->d_name, 53-2);\r
+               }\r
+       }\r
+       gp2x_text_out15(5, 120, ">");\r
+       gp2x_video_flip();\r
+}\r
+\r
+static int scandir_cmp(const void *p1, const void *p2)\r
+{\r
+       struct dirent **d1 = (struct dirent **)p1, **d2 = (struct dirent **)p2;\r
+       if ((*d1)->d_type == (*d2)->d_type) return alphasort(d1, d2);\r
+       if ((*d1)->d_type == DT_DIR) return -1; // put before\r
+       if ((*d2)->d_type == DT_DIR) return  1;\r
+       return alphasort(d1, d2);\r
+}\r
+\r
+static char *filter_exts[] = {\r
+       // TODO\r
+       ".mp3", ".MP3", ".srm", ".brm", "s.gz", ".mds", "bcfg", ".txt", ".htm", "html",\r
+       ".jpg", ".gpe", ".cue"\r
+};\r
+\r
+static int scandir_filter(const struct dirent *ent)\r
+{\r
+       const char *p;\r
+       int i;\r
+\r
+       if (ent == NULL || ent->d_name == NULL) return 0;\r
+       if (strlen(ent->d_name) < 5) return 1;\r
+\r
+       p = ent->d_name + strlen(ent->d_name) - 4;\r
+\r
+       for (i = 0; i < sizeof(filter_exts)/sizeof(filter_exts[0]); i++)\r
+       {\r
+               if (strcmp(p, filter_exts[i]) == 0) return 0;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+static char *romsel_loop(char *curr_path)\r
+{\r
+       struct dirent **namelist;\r
+       DIR *dir;\r
+       int n, sel = 0;\r
+       unsigned long inp = 0;\r
+       char *ret = NULL, *fname = NULL;\r
+\r
+       // is this a dir or a full path?\r
+       if ((dir = opendir(curr_path))) {\r
+               closedir(dir);\r
+       } else {\r
+               char *p;\r
+               for (p = curr_path + strlen(curr_path) - 1; p > curr_path && *p != '/'; p--);\r
+               *p = 0;\r
+               fname = p+1;\r
+       }\r
+\r
+       n = scandir(curr_path, &namelist, scandir_filter, scandir_cmp);\r
+       if (n < 0) {\r
+               // try root\r
+               n = scandir("/", &namelist, scandir_filter, scandir_cmp);\r
+               if (n < 0) {\r
+                       // oops, we failed\r
+                       printf("dir: %s\n", curr_path);\r
+                       perror("scandir");\r
+                       return NULL;\r
+               }\r
+       }\r
+\r
+       // try to find sel\r
+       if (fname != NULL) {\r
+               int i;\r
+               for (i = 1; i < n; i++) {\r
+                       if (strcmp(namelist[i]->d_name, fname) == 0) {\r
+                               sel = i - 1;\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+\r
+       for (;;)\r
+       {\r
+               draw_dirlist(curr_path, namelist, n, sel);\r
+               inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_L|GP2X_R|GP2X_B|GP2X_X);\r
+               if(inp & GP2X_UP  )  { sel--;   if (sel < 0)   sel = n-2; }\r
+               if(inp & GP2X_DOWN)  { sel++;   if (sel > n-2) sel = 0; }\r
+               if(inp & GP2X_LEFT)  { sel-=10; if (sel < 0)   sel = 0; }\r
+               if(inp & GP2X_L)     { sel-=24; if (sel < 0)   sel = 0; }\r
+               if(inp & GP2X_RIGHT) { sel+=10; if (sel > n-2) sel = n-2; }\r
+               if(inp & GP2X_R)     { sel+=24; if (sel > n-2) sel = n-2; }\r
+               if(inp & GP2X_B)     { // enter dir/select\r
+                       again:\r
+                       if (namelist[sel+1]->d_type == DT_REG) {\r
+                               strcpy(lastLoadedGameName, curr_path);\r
+                               strcat(lastLoadedGameName, "/");\r
+                               strcat(lastLoadedGameName, namelist[sel+1]->d_name);\r
+                               ret = lastLoadedGameName;\r
+                               break;\r
+                       } else if (namelist[sel+1]->d_type == DT_DIR) {\r
+                               int newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2;\r
+                               char *p, *newdir = malloc(newlen);\r
+                               if (strcmp(namelist[sel+1]->d_name, "..") == 0) {\r
+                                       char *start = curr_path;\r
+                                       p = start + strlen(start) - 1;\r
+                                       while (*p == '/' && p > start) p--;\r
+                                       while (*p != '/' && p > start) p--;\r
+                                       if (p <= start) strcpy(newdir, "/");\r
+                                       else { strncpy(newdir, start, p-start); newdir[p-start] = 0; }\r
+                               } else {\r
+                                       strcpy(newdir, curr_path);\r
+                                       p = newdir + strlen(newdir) - 1;\r
+                                       while (*p == '/' && p >= newdir) *p-- = 0;\r
+                                       strcat(newdir, "/");\r
+                                       strcat(newdir, namelist[sel+1]->d_name);\r
+                               }\r
+                               ret = romsel_loop(newdir);\r
+                               free(newdir);\r
+                               break;\r
+                       } else {\r
+                               // unknown file type, happens on NTFS mounts. Try to guess.\r
+                               FILE *tstf; int tmp;\r
+                               strcpy(lastLoadedGameName, curr_path);\r
+                               strcat(lastLoadedGameName, "/");\r
+                               strcat(lastLoadedGameName, namelist[sel+1]->d_name);\r
+                               tstf = fopen(lastLoadedGameName, "rb");\r
+                               if (tstf != NULL)\r
+                               {\r
+                                       if (fread(&tmp, 1, 1, tstf) > 0 || ferror(tstf) == 0)\r
+                                               namelist[sel+1]->d_type = DT_REG;\r
+                                       else    namelist[sel+1]->d_type = DT_DIR;\r
+                                       fclose(tstf);\r
+                                       goto again;\r
+                               }\r
+                       }\r
+               }\r
+               if(inp & GP2X_X) break; // cancel\r
+       }\r
+\r
+       if (n > 0) {\r
+               while(n--) free(namelist[n]);\r
+               free(namelist);\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+// ------------ patch/gg menu ------------\r
+\r
+#if 0 // TODO?\r
+static void draw_patchlist(int sel)\r
+{\r
+       int start, i, pos;\r
+\r
+       start = 12 - sel;\r
+\r
+       gp2x_fceu_copy_bg();\r
+\r
+       for (i = 0; i < PicoPatchCount; i++) {\r
+               pos = start + i;\r
+               if (pos < 0)  continue;\r
+               if (pos > 23) break;\r
+               gp2x_smalltext8_lim(14,     pos*10, PicoPatches[i].active ? "ON " : "OFF", 3);\r
+               gp2x_smalltext8_lim(14+6*4, pos*10, PicoPatches[i].name, 53-6);\r
+       }\r
+       pos = start + i;\r
+       if (pos < 24) gp2x_smalltext8_lim(14, pos*10, "done", 4);\r
+\r
+       gp2x_text_out15(5, 120, ">");\r
+       gp2x_video_flip();\r
+}\r
+\r
+\r
+void patches_menu_loop(void)\r
+{\r
+       int menu_sel = 0;\r
+       unsigned long inp = 0;\r
+\r
+       for(;;)\r
+       {\r
+               draw_patchlist(menu_sel);\r
+               inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_L|GP2X_R|GP2X_B|GP2X_X);\r
+               if(inp & GP2X_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = PicoPatchCount; }\r
+               if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > PicoPatchCount) menu_sel = 0; }\r
+               if(inp &(GP2X_LEFT|GP2X_L))  { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }\r
+               if(inp &(GP2X_RIGHT|GP2X_R)) { menu_sel+=10; if (menu_sel > PicoPatchCount) menu_sel = PicoPatchCount; }\r
+               if(inp & GP2X_B) { // action\r
+                       if (menu_sel < PicoPatchCount)\r
+                               PicoPatches[menu_sel].active = !PicoPatches[menu_sel].active;\r
+                       else    return;\r
+               }\r
+               if(inp & GP2X_X) return;\r
+       }\r
+\r
+}\r
+\r
+// ------------ savestate loader ------------\r
+\r
+static void menu_prepare_bg(void);\r
+\r
+static int state_slot_flags = 0;\r
+\r
+static void state_check_slots(void)\r
+{\r
+       int slot;\r
+\r
+       state_slot_flags = 0;\r
+\r
+       for (slot = 0; slot < 10; slot++)\r
+       {\r
+               if (emu_check_save_file(slot))\r
+               {\r
+                       state_slot_flags |= 1 << slot;\r
+               }\r
+       }\r
+}\r
+\r
+static void draw_savestate_bg(int slot)\r
+{\r
+       struct PicoVideo tmp_pv;\r
+       unsigned short tmp_cram[0x40];\r
+       unsigned short tmp_vsram[0x40];\r
+       void *tmp_vram, *file;\r
+       char *fname;\r
+\r
+       fname = emu_GetSaveFName(1, 0, slot);\r
+       if (!fname) return;\r
+\r
+       tmp_vram = malloc(sizeof(Pico.vram));\r
+       if (tmp_vram == NULL) return;\r
+\r
+       memcpy(tmp_vram, Pico.vram, sizeof(Pico.vram));\r
+       memcpy(tmp_cram, Pico.cram, sizeof(Pico.cram));\r
+       memcpy(tmp_vsram, Pico.vsram, sizeof(Pico.vsram));\r
+       memcpy(&tmp_pv, &Pico.video, sizeof(Pico.video));\r
+\r
+       if (strcmp(fname + strlen(fname) - 3, ".gz") == 0) {\r
+               file = gzopen(fname, "rb");\r
+               emu_set_save_cbs(1);\r
+       } else {\r
+               file = fopen(fname, "rb");\r
+               emu_set_save_cbs(0);\r
+       }\r
+\r
+       if (file) {\r
+               if (PicoMCD & 1) {\r
+                       PicoCdLoadStateGfx(file);\r
+               } else {\r
+                       areaSeek(file, 0x10020, SEEK_SET);  // skip header and RAM in state file\r
+                       areaRead(Pico.vram, 1, sizeof(Pico.vram), file);\r
+                       areaSeek(file, 0x2000, SEEK_CUR);\r
+                       areaRead(Pico.cram, 1, sizeof(Pico.cram), file);\r
+                       areaRead(Pico.vsram, 1, sizeof(Pico.vsram), file);\r
+                       areaSeek(file, 0x221a0, SEEK_SET);\r
+                       areaRead(&Pico.video, 1, sizeof(Pico.video), file);\r
+               }\r
+               areaClose(file);\r
+       }\r
+\r
+       emu_forced_frame();\r
+       gp2x_memcpy_buffers((1<<2), gp2x_screen, 0, 320*240*2);\r
+       menu_prepare_bg();\r
+\r
+       memcpy(Pico.vram, tmp_vram, sizeof(Pico.vram));\r
+       memcpy(Pico.cram, tmp_cram, sizeof(Pico.cram));\r
+       memcpy(Pico.vsram, tmp_vsram, sizeof(Pico.vsram));\r
+       memcpy(&Pico.video, &tmp_pv,  sizeof(Pico.video));\r
+       free(tmp_vram);\r
+}\r
+\r
+static void draw_savestate_menu(int menu_sel, int is_loading)\r
+{\r
+       int tl_x = 25, tl_y = 60, y, i;\r
+\r
+       if (state_slot_flags & (1 << menu_sel))\r
+               draw_savestate_bg(menu_sel);\r
+       gp2x_fceu_copy_bg();\r
+\r
+       gp2x_text_out15(tl_x, 30, is_loading ? "Load state" : "Save state");\r
+\r
+       /* draw all 10 slots */\r
+       y = tl_y;\r
+       for (i = 0; i < 10; i++, y+=10)\r
+       {\r
+               gp2x_text_out15(tl_x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free");\r
+       }\r
+       gp2x_text_out15(tl_x, y, "back");\r
+\r
+       // draw cursor\r
+       gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
+\r
+       gp2x_video_flip();\r
+}\r
+\r
+static int savestate_menu_loop(int is_loading)\r
+{\r
+       int menu_sel = 10, menu_sel_max = 10;\r
+       unsigned long inp = 0;\r
+\r
+       state_check_slots();\r
+\r
+       for(;;)\r
+       {\r
+               draw_savestate_menu(menu_sel, is_loading);\r
+               inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
+               if(inp & GP2X_UP  ) {\r
+                       do {\r
+                               menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max;\r
+                       } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
+               }\r
+               if(inp & GP2X_DOWN) {\r
+                       do {\r
+                               menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0;\r
+                       } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
+               }\r
+               if(inp & GP2X_B) { // save/load\r
+                       if (menu_sel < 10) {\r
+                               state_slot = menu_sel;\r
+                               if (emu_SaveLoadGame(is_loading, 0)) {\r
+                                       strcpy(menuErrorMsg, is_loading ? "Load failed" : "Save failed");\r
+                                       return 1;\r
+                               }\r
+                               return 0;\r
+                       } else  return 1;\r
+               }\r
+               if(inp & GP2X_X) return 1;\r
+       }\r
+}\r
+\r
+// -------------- key config --------------\r
+\r
+static char *usb_joy_key_name(int joy, int num)\r
+{\r
+       static char name[16];\r
+       switch (num)\r
+       {\r
+               case 0: sprintf(name, "Joy%i UP", joy); break;\r
+               case 1: sprintf(name, "Joy%i DOWN", joy); break;\r
+               case 2: sprintf(name, "Joy%i LEFT", joy); break;\r
+               case 3: sprintf(name, "Joy%i RIGHT", joy); break;\r
+               default:sprintf(name, "Joy%i b%i", joy, num-3); break;\r
+       }\r
+       return name;\r
+}\r
+\r
+static void draw_key_config(int curr_act, int is_p2)\r
+{\r
+       char strkeys[32*5];\r
+       int joy, i;\r
+\r
+       strkeys[0] = 0;\r
+       for (i = 0; i < 32; i++)\r
+       {\r
+               if (currentConfig.KeyBinds[i] & (1 << curr_act))\r
+               {\r
+                       if (curr_act < 16 && (currentConfig.KeyBinds[i] & (1 << 16)) != (is_p2 << 16)) continue;\r
+                       if (strkeys[0]) { strcat(strkeys, " + "); strcat(strkeys, gp2xKeyNames[i]); break; }\r
+                       else strcpy(strkeys, gp2xKeyNames[i]);\r
+               }\r
+       }\r
+       for (joy = 0; joy < num_of_joys; joy++)\r
+       {\r
+               for (i = 0; i < 32; i++)\r
+               {\r
+                       if (currentConfig.JoyBinds[joy][i] & (1 << curr_act))\r
+                       {\r
+                               if (curr_act < 16 && (currentConfig.JoyBinds[joy][i] & (1 << 16)) != (is_p2 << 16)) continue;\r
+                               if (strkeys[0]) {\r
+                                       strcat(strkeys, ", "); strcat(strkeys, usb_joy_key_name(joy + 1, i));\r
+                                       break;\r
+                               }\r
+                               else strcpy(strkeys, usb_joy_key_name(joy + 1, i));\r
+                       }\r
+               }\r
+       }\r
+\r
+       //memset(gp2x_screen, 0, 320*240);\r
+       gp2x_fceu_copy_bg();\r
+       gp2x_text_out15(60, 40, "Action: %s", actionNames[curr_act]);\r
+       gp2x_text_out15(60, 60, "Keys: %s", strkeys);\r
+\r
+       gp2x_text_out15(30, 180, "Use SELECT to change action");\r
+       gp2x_text_out15(30, 190, "Press a key to bind/unbind");\r
+       gp2x_text_out15(30, 200, "Select \"Done\" action and");\r
+       gp2x_text_out15(30, 210, "  press any key to finish");\r
+       gp2x_video_flip();\r
+}\r
+\r
+static void key_config_loop(int is_p2)\r
+{\r
+       int curr_act = 0, joy = 0, i;\r
+       unsigned long inp = 0;\r
+\r
+       for (;;)\r
+       {\r
+               draw_key_config(curr_act, is_p2);\r
+               inp = wait_for_input_usbjoy(CONFIGURABLE_KEYS, &joy);\r
+               // printf("got %08lX from joy %i\n", inp, joy);\r
+               if (joy == 0) {\r
+                       if (inp & GP2X_SELECT) {\r
+                               curr_act++;\r
+                               while (!actionNames[curr_act] && curr_act < 32) curr_act++;\r
+                               if (curr_act > 31) curr_act = 0;\r
+                       }\r
+                       inp &= CONFIGURABLE_KEYS;\r
+                       inp &= ~GP2X_SELECT;\r
+               }\r
+               if (curr_act == 31 && inp) break;\r
+               if (joy == 0) {\r
+                       for (i = 0; i < 32; i++)\r
+                               if (inp & (1 << i)) {\r
+                                       currentConfig.KeyBinds[i] ^= (1 << curr_act);\r
+                                       if (is_p2) currentConfig.KeyBinds[i] |=  (1 << 16); // player 2 flag\r
+                                       else       currentConfig.KeyBinds[i] &= ~(1 << 16);\r
+                               }\r
+               } else {\r
+                       for (i = 0; i < 32; i++)\r
+                               if (inp & (1 << i)) {\r
+                                       currentConfig.JoyBinds[joy-1][i] ^= (1 << curr_act);\r
+                                       if (is_p2) currentConfig.JoyBinds[joy-1][i] |=  (1 << 16);\r
+                                       else       currentConfig.JoyBinds[joy-1][i] &= ~(1 << 16);\r
+                               }\r
+               }\r
+       }\r
+}\r
+\r
+static void draw_kc_sel(int menu_sel)\r
+{\r
+       int tl_x = 25+40, tl_y = 60, y, i;\r
+       char joyname[36];\r
+\r
+       y = tl_y;\r
+       //memset(gp2x_screen, 0, 320*240);\r
+       gp2x_fceu_copy_bg();\r
+       gp2x_text_out15(tl_x, y,       "Player 1");\r
+       gp2x_text_out15(tl_x, (y+=10), "Player 2");\r
+       gp2x_text_out15(tl_x, (y+=10), "Done");\r
+\r
+       // draw cursor\r
+       gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
+\r
+       tl_x = 25;\r
+       gp2x_text_out15(tl_x, (y=110), "USB joys detected:");\r
+       if (num_of_joys > 0) {\r
+               for (i = 0; i < num_of_joys; i++) {\r
+                       strncpy(joyname, joy_name(joys[i]), 33); joyname[33] = 0;\r
+                       gp2x_text_out15(tl_x, (y+=10), "%i: %s", i+1, joyname);\r
+               }\r
+       } else {\r
+               gp2x_text_out15(tl_x, (y+=10), "none");\r
+       }\r
+\r
+\r
+       gp2x_video_flip();\r
+}\r
+\r
+static void kc_sel_loop(void)\r
+{\r
+       int menu_sel = 2, menu_sel_max = 2;\r
+       unsigned long inp = 0;\r
+\r
+       for(;;)\r
+       {\r
+               draw_kc_sel(menu_sel);\r
+               inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
+               if(inp & GP2X_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
+               if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
+               if(inp & GP2X_B) {\r
+                       switch (menu_sel) {\r
+                               case 0: key_config_loop(0); return;\r
+                               case 1: key_config_loop(1); return;\r
+                               default: return;\r
+                       }\r
+               }\r
+               if(inp & GP2X_X) return;\r
+       }\r
+}\r
+#endif\r
+\r
+\r
+\r
+// --------- advanced options ----------\r
+#if 0\r
+static void draw_amenu_options(int menu_sel)\r
+{\r
+       int tl_x = 25, tl_y = 60, y;\r
+       char *mms = mmuhack_status ? "active)  " : "inactive)";\r
+\r
+       y = tl_y;\r
+       //memset(gp2x_screen, 0, 320*240);\r
+       gp2x_fceu_copy_bg();\r
+\r
+       gp2x_text_out15(tl_x, y,       "Gamma correction           %i.%02i", currentConfig.gamma / 100, currentConfig.gamma%100); // 0\r
+       gp2x_text_out15(tl_x, (y+=10), "Don't save last used ROM   %s", (currentConfig.EmuOpt &0x020)?"ON":"OFF"); // 5\r
+       gp2x_text_out15(tl_x, (y+=10), "needs restart:");\r
+       gp2x_text_out15(tl_x, (y+=10), "craigix's RAM timings      %s", (currentConfig.EmuOpt &0x100)?"ON":"OFF"); // 7\r
+       gp2x_text_out15(tl_x, (y+=10), "squidgehack (now %s %s",   mms, (currentConfig.EmuOpt &0x010)?"ON":"OFF"); // 8\r
+       gp2x_text_out15(tl_x, (y+=10), "Done");\r
+\r
+       // draw cursor\r
+       gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
+\r
+       gp2x_video_flip();\r
+}\r
+\r
+static void amenu_loop_options(void)\r
+{\r
+       int menu_sel = 0, menu_sel_max = 9;\r
+       unsigned long inp = 0;\r
+\r
+       for(;;)\r
+       {\r
+               draw_amenu_options(menu_sel);\r
+               inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);\r
+               if(inp & GP2X_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
+               if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
+               if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options\r
+                       switch (menu_sel) {\r
+                               case  1: break;\r
+                               case  9: return;\r
+                       }\r
+               }\r
+               if(inp & (GP2X_X|GP2X_A)) return;\r
+               if(inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise\r
+                       switch (menu_sel) {\r
+                               case 0:\r
+                                       while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
+                                               currentConfig.gamma += (inp & GP2X_LEFT) ? -1 : 1;\r
+                                               if (currentConfig.gamma <   1) currentConfig.gamma =   1;\r
+                                               if (currentConfig.gamma > 300) currentConfig.gamma = 300;\r
+                                               draw_amenu_options(menu_sel);\r
+                                               usleep(18*1000);\r
+                                       }\r
+                                       break;\r
+                       }\r
+               }\r
+       }\r
+}\r
+#endif\r
+\r
+// -------------- options --------------\r
+\r
+static void draw_menu_options(int menu_sel)\r
+{\r
+       int tl_x = 25, tl_y = 32, y;\r
+       char monostereo[8], strframeskip[8], *strscaling, *strssconfirm;\r
+\r
+       //strcpy(monostereo, (currentConfig.PicoOpt&0x08)?"stereo":"mono");\r
+       if (Settings.frameskip < 0)\r
+            strcpy(strframeskip, "Auto");\r
+       else sprintf(strframeskip, "%i", Settings.frameskip);\r
+       switch (Settings.scaling) {\r
+               default: strscaling = "            OFF";   break;\r
+               case 1:  strscaling = "hw horizontal";     break;\r
+               case 2:  strscaling = "hw horiz. + vert."; break;\r
+               case 3:  strscaling = "sw horizontal";     break;\r
+       }\r
+       switch (Settings.sstate_confirm) {\r
+               default: strssconfirm = "OFF";    break;\r
+               case 1:  strssconfirm = "writes"; break;\r
+               case 2:  strssconfirm = "loads";  break;\r
+               case 3:  strssconfirm = "both";   break;\r
+       }\r
+\r
+       y = tl_y;\r
+       //memset(gp2x_screen, 0, 320*240);\r
+       gp2x_fceu_copy_bg();\r
+\r
+       gp2x_text_out15(tl_x, (y+=10), "Scaling:       %s", strscaling);                                // 0\r
+       gp2x_text_out15(tl_x, (y+=10), "Show FPS                   %s", Settings.showfps?"ON":"OFF");   // 1\r
+       gp2x_text_out15(tl_x, (y+=10), "Frameskip                  %s", strframeskip);                  // 2\r
+       gp2x_text_out15(tl_x, (y+=10), "Enable sound               %s", /*(currentConfig.EmuOpt &0x004)?"ON":*/"OFF"); // 3\r
+       gp2x_text_out15(tl_x, (y+=10), "Sound Quality:     %5iHz %s",   0, "" /*currentConfig.PsndRate, monostereo*/); // 4\r
+       gp2x_text_out15(tl_x, (y+=10), "Region:              %s",\r
+               Settings.region_force == 2 ? "NTSC" : Settings.region_force == 1 ? "PAL" : "OFF");      // 5\r
+       gp2x_text_out15(tl_x, (y+=10), "Use SRAM savestates        %s", "OFF");\r
+       gp2x_text_out15(tl_x, (y+=10), "Confirm savestate          %s", strssconfirm);\r
+       gp2x_text_out15(tl_x, (y+=10), "Save slot                  %i", 0/*state_slot*/);               // 8\r
+       gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock             %iMhz", Settings.cpuclock);\r
+       gp2x_text_out15(tl_x, (y+=10), "[advanced options]");                                           // 10\r
+       gp2x_text_out15(tl_x, (y+=10), "Save cfg as default");\r
+       if (fceugi)\r
+               gp2x_text_out15(tl_x, (y+=10), "Save cfg for current game only");\r
+\r
+       // draw cursor\r
+       gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
+\r
+       gp2x_video_flip();\r
+}\r
+\r
+/*\r
+static int sndrate_prevnext(int rate, int dir)\r
+{\r
+       int i, rates[] = { 8000, 11025, 16000, 22050, 44100 };\r
+\r
+       for (i = 0; i < 5; i++)\r
+               if (rates[i] == rate) break;\r
+\r
+       i += dir ? 1 : -1;\r
+       if (i > 4) return dir ? 44100 : 22050;\r
+       if (i < 0) return dir ? 11025 : 8000;\r
+       return rates[i];\r
+}\r
+*/\r
+static void int_incdec(int *p, int inc, int min, int max)\r
+{\r
+       *p += inc;\r
+       if      (*p < min) *p = min;\r
+       else if (*p > max) *p = max;\r
+}\r
+\r
+static int menu_loop_options(void)\r
+{\r
+       int menu_sel = 0, menu_sel_max = 11;\r
+       unsigned long inp = 0;\r
+\r
+       if (fceugi) menu_sel_max++;\r
+\r
+       for(;;)\r
+       {\r
+               draw_menu_options(menu_sel);\r
+               inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);\r
+               if(inp & GP2X_UP  ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
+               if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
+               if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options\r
+                       switch (menu_sel) {\r
+                               case  1: Settings.showfps = !Settings.showfps; break;\r
+                               //case  6: Settings. = !Settings.showfps; break;\r
+                               //case 16: amenu_loop_options();    break;\r
+                               case 17: // done (update and write)\r
+                                       //if (emu_WriteConfig(0)) strcpy(menuErrorMsg, "config saved");\r
+                                       //else strcpy(menuErrorMsg, "failed to write config");\r
+                                       return 1;\r
+                               case 18: // done (update and write for current game)\r
+                                       //if (emu_WriteConfig(1)) strcpy(menuErrorMsg, "config saved");\r
+                                       //else strcpy(menuErrorMsg, "failed to write config");\r
+                                       return 1;\r
+                       }\r
+               }\r
+               if(inp & (GP2X_X|GP2X_A)) {\r
+                       return 0;  // done (update, no write)\r
+               }\r
+               if(inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise\r
+                       switch (menu_sel) {\r
+                               case  0: int_incdec(&Settings.scaling,   (inp & GP2X_LEFT) ? -1 : 1,  0,  3); break;\r
+                               case  2: int_incdec(&Settings.frameskip, (inp & GP2X_LEFT) ? -1 : 1, -1, 32); break;\r
+/*\r
+                               case  4:\r
+                                       if ((inp & GP2X_RIGHT) && currentConfig.PsndRate == 44100 && !(currentConfig.PicoOpt&0x08)) {\r
+                                               currentConfig.PsndRate = 8000;  currentConfig.PicoOpt|= 0x08;\r
+                                       } else if ((inp & GP2X_LEFT) && currentConfig.PsndRate == 8000 && (currentConfig.PicoOpt&0x08)) {\r
+                                               currentConfig.PsndRate = 44100; currentConfig.PicoOpt&=~0x08;\r
+                                       } else currentConfig.PsndRate = sndrate_prevnext(currentConfig.PsndRate, inp & GP2X_RIGHT);\r
+                                       break;\r
+*/\r
+                               case  5: int_incdec(&Settings.region_force,   (inp & GP2X_LEFT) ? -1 : 1, 0, 2); break;\r
+                               case  7: int_incdec(&Settings.sstate_confirm, (inp & GP2X_LEFT) ? -1 : 1, 0, 3); break;\r
+                               //case  8: int_incdec(&Settings., (inp & GP2X_LEFT) ? -1 : 1, 0, 9); break;\r
+                               case 14:\r
+                                       while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
+                                               Settings.cpuclock += (inp & GP2X_LEFT) ? -1 : 1;\r
+                                               if (Settings.cpuclock < 1) Settings.cpuclock = 1;\r
+                                               draw_menu_options(menu_sel);\r
+                                               usleep(50*1000);\r
+                                       }\r
+                                       break;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+// -------------- credits --------------\r
+\r
+static void draw_menu_credits(void)\r
+{\r
+       int tl_x = 15, tl_y = 70, y;\r
+       //memset(gp2x_screen, 0, 320*240);\r
+       gp2x_fceu_copy_bg();\r
+\r
+       // TODO\r
+\r
+       gp2x_video_flip();\r
+}\r
+\r
+\r
+// -------------- root menu --------------\r
+\r
+static void draw_menu_root(int menu_sel)\r
+{\r
+       int tl_x = 70, tl_y = 70, y;\r
+       gp2x_fceu_copy_bg();\r
+\r
+       y = tl_y;\r
+       if (fceugi) {\r
+               gp2x_text_out15(tl_x, y,       "Resume game");\r
+               gp2x_text_out15(tl_x, (y+=10), "Save State");\r
+               gp2x_text_out15(tl_x, (y+=10), "Load State");\r
+               gp2x_text_out15(tl_x, (y+=10), "Reset game");\r
+       } else {\r
+               y += 30;\r
+       }\r
+       gp2x_text_out15(tl_x, (y+=10), "Load new ROM");\r
+       gp2x_text_out15(tl_x, (y+=10), "Change options");\r
+       gp2x_text_out15(tl_x, (y+=10), "Configure controls");\r
+       gp2x_text_out15(tl_x, (y+=10), "Credits");\r
+       gp2x_text_out15(tl_x, (y+=10), "Exit");\r
+// TODO\r
+//     if (PicoPatches)\r
+//             gp2x_text_out15(tl_x, (y+=10), "Patches / GameGenie");\r
+\r
+       // draw cursor\r
+       gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">");\r
+       // error\r
+       if (menuErrorMsg[0]) gp2x_text_out15(5, 226, menuErrorMsg);\r
+       gp2x_video_flip();\r
+}\r
+\r
+\r
+static int menu_loop_root(void)\r
+{\r
+       int ret, menu_sel = 4, menu_sel_max = 8, menu_sel_min = 4;\r
+       unsigned long inp = 0;\r
+       char curr_path[PATH_MAX], *selfname;\r
+       FILE *tstf;\r
+\r
+       if ( (tstf = fopen(lastLoadedGameName, "rb")) )\r
+       {\r
+               fclose(tstf);\r
+               strncpy(curr_path, lastLoadedGameName, sizeof(curr_path));\r
+               curr_path[sizeof(curr_path)-1] = 0;\r
+       }\r
+       else\r
+       {\r
+               getcwd(curr_path, PATH_MAX);\r
+       }\r
+\r
+       if (fceugi) menu_sel = menu_sel_min = 0;\r
+// TODO        if (PicoPatches) menu_sel_max = 9;\r
+\r
+       /* make sure action buttons are not pressed on entering menu */\r
+       draw_menu_root(menu_sel);\r
+       while (gp2x_joystick_read(1) & (GP2X_B|GP2X_X|GP2X_SELECT)) usleep(50*1000);\r
+\r
+       for (;;)\r
+       {\r
+               draw_menu_root(menu_sel);\r
+               inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
+               if(inp & GP2X_UP  )  { menu_sel--; if (menu_sel < menu_sel_min) menu_sel = menu_sel_max; }\r
+               if(inp & GP2X_DOWN)  { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = menu_sel_min; }\r
+               if(inp &(GP2X_SELECT|GP2X_X)){\r
+                       if (fceugi) {\r
+                               while (gp2x_joystick_read(1) & GP2X_X) usleep(50*1000); // wait until X is released\r
+                               Exit = 0;\r
+                               return 0;\r
+                       }\r
+               }\r
+               if(inp & GP2X_B   )  {\r
+                       switch (menu_sel) {\r
+                               case 0: // resume game\r
+                                       if (fceugi) {\r
+                                               while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
+                                               Exit = 0;\r
+                                               return 0;\r
+                                       }\r
+                                       break;\r
+                               case 1: // save state\r
+                                       if (fceugi) {\r
+                                               /*if(savestate_menu_loop(0))\r
+                                                       continue;*/\r
+                                               return 0;\r
+                                       }\r
+                                       break;\r
+                               case 2: // load state\r
+                                       if (fceugi) {\r
+                                               /*if(savestate_menu_loop(1))\r
+                                                       continue;*/\r
+                                               return 0;\r
+                                       }\r
+                                       break;\r
+                               case 3: // reset game\r
+                                       if (fceugi) {\r
+                                               return 0;\r
+                                       }\r
+                                       break;\r
+                               case 4: // select rom\r
+                                       selfname = romsel_loop(curr_path);\r
+                                       if (selfname) {\r
+                                               printf("selected file: %s\n", selfname);\r
+                                               return 2;\r
+                                       }\r
+                                       break;\r
+                               case 5: // options\r
+                                       ret = menu_loop_options();\r
+                                       if (ret == 1) continue; // status update\r
+                                       break;\r
+                               case 6: // controls\r
+                                       // TODO kc_sel_loop();\r
+                                       break;\r
+                               case 7: // credits\r
+                                       draw_menu_credits();\r
+                                       usleep(500*1000);\r
+                                       inp = wait_for_input(GP2X_B|GP2X_X);\r
+                                       break;\r
+                               case 8: // exit\r
+                                       return 1;\r
+                               case 9: // patches/gg\r
+                                       break;\r
+                       }\r
+               }\r
+               menuErrorMsg[0] = 0; // clear error msg\r
+       }\r
+}\r
+\r
+\r
+static void menu_prepare_bg(void)\r
+{\r
+       // TODO...\r
+}\r
+\r
+static void menu_gfx_prepare(void)\r
+{\r
+       menu_prepare_bg();\r
+\r
+       // switch bpp\r
+       gp2x_video_changemode(16);\r
+       gp2x_video_RGB_setscaling(0, 320, 240);\r
+       gp2x_video_flip();\r
+}\r
+\r
+\r
+int gp2x_menu_do(void)\r
+{\r
+       int ret;\r
+\r
+       menu_gfx_prepare();\r
+\r
+       ret = menu_loop_root();\r
+\r
+       menuErrorMsg[0] = 0;\r
+\r
+       return ret;\r
+}\r
+\r
+\r
diff --git a/drivers/gp2x/menu.h b/drivers/gp2x/menu.h
new file mode 100644 (file)
index 0000000..f673197
--- /dev/null
@@ -0,0 +1,5 @@
+
+extern char menuErrorMsg[40];
+
+int gp2x_menu_do(void);
+
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
index ecafd75..37507f0 100644 (file)
-/*\r
 \r
 \r
-  GP2X minimal library v0.A by rlyeh, (c) 2005. emulnation.info@rlyeh (swap it!)\r
+#ifndef __GP2X_H__\r
+#define __GP2X_H__\r
 \r
 \r
-  Thanks to Squidge, Robster, snaff, Reesy and NK, for the help & previous work! :-)\r
 \r
 \r
-  License\r
-  =======\r
+void gp2x_init(void);\r
+void gp2x_deinit(void);\r
 \r
 \r
-  Free for non-commercial projects (it would be nice receiving a mail from you).\r
-  Other cases, ask me first.\r
+/* video */\r
+void gp2x_video_flip(void);\r
+void gp2x_video_changemode(int bpp);\r
+void gp2x_video_changemode2(int bpp);\r
+void gp2x_video_setpalette(int *pal, int len);\r
+void gp2x_video_RGB_setscaling(int ln_offs, int W, int H);\r
+void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len);\r
+void gp2x_memcpy_all_buffers(void *data, int offset, int len);\r
+void gp2x_memset_all_buffers(int offset, int byte, int len);\r
 \r
 \r
-  GamePark Holdings is not allowed to use this library and/or use parts from it.\r
+/* sound */\r
+void gp2x_start_sound(int rate, int bits, int stereo);\r
+void gp2x_sound_write(void *buff, int len);\r
+void gp2x_sound_volume(int l, int r);\r
 \r
 \r
-*/\r
+/* joy */\r
+unsigned long gp2x_joystick_read(int allow_usb_joy);\r
 \r
 \r
-#include <fcntl.h>\r
-#include <linux/fb.h>\r
-#include <signal.h>\r
-#include <stdlib.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <sys/mman.h>\r
-//#include <sys/ioctl.h>\r
-#include <sys/soundcard.h>\r
-#include <linux/soundcard.h>\r
 \r
 \r
-#include <sys/time.h>\r
-#include <unistd.h>\r
-#include <sys/ioctl.h>\r
+extern void *gp2x_screen;\r
+extern int memdev;\r
+extern char *ext_menu, *ext_state;\r
 \r
 \r
-#ifndef __MINIMAL_H__\r
-#define __MINIMAL_H__\r
-\r
-#define MINILIB_VERSION  "GP2X minimal library v0.A by rlyeh, (c) 2005."\r
-\r
-typedef struct gp2x_queue { volatile unsigned long head, tail, items, max_items; unsigned long *place920t, *place940t; } gp2x_queue;\r
-typedef struct gp2x_rect  { int x,y,w,h,solid; unsigned short *data15; unsigned char *data8; } gp2x_rect;\r
-\r
-extern void gp2x_timer_delay(unsigned long ticks);\r
-extern void gp2x_sound_pause(int yes);\r
-extern void gp2x_dualcore_pause(int yes);\r
-extern void             gp2x_blitter_rect15(gp2x_rect *r);\r
-extern void             gp2x_blitter_rect8(gp2x_rect *r);\r
-\r
-\r
-\r
-//extern void             gp2x_sound_frame (void *blah, void *bufferg, int samples);\r
 \r
 enum  { GP2X_UP=0x1,       GP2X_LEFT=0x4,       GP2X_DOWN=0x10,  GP2X_RIGHT=0x40,\r
         GP2X_START=1<<8,   GP2X_SELECT=1<<9,    GP2X_L=1<<10,    GP2X_R=1<<11,\r
         GP2X_A=1<<12,      GP2X_B=1<<13,        GP2X_X=1<<14,    GP2X_Y=1<<15,\r
 \r
 enum  { GP2X_UP=0x1,       GP2X_LEFT=0x4,       GP2X_DOWN=0x10,  GP2X_RIGHT=0x40,\r
         GP2X_START=1<<8,   GP2X_SELECT=1<<9,    GP2X_L=1<<10,    GP2X_R=1<<11,\r
         GP2X_A=1<<12,      GP2X_B=1<<13,        GP2X_X=1<<14,    GP2X_Y=1<<15,\r
-        GP2X_VOL_UP=1<<23, GP2X_VOL_DOWN=1<<22, GP2X_PUSH=1<<27                   };\r
-\r
-\r
-#define GP2X_QUEUE_MAX_ITEMS           16\r
-#define GP2X_QUEUE_ARRAY_PTR           ((0x1000-(sizeof(gp2x_queue)<<2)))\r
-#define GP2X_QUEUE_DATA_PTR            (GP2X_QUEUE_ARRAY_PTR-(GP2X_QUEUE_MAX_ITEMS<<2))\r
-\r
-#define gp2x_2ndcore_code(v)           (*(volatile unsigned long *)(v))\r
-#define gp2x_1stcore_code(v)           gp2x_dualcore_ram[(v)>>2]\r
-#define gp2x_2ndcore_data(v)           gp2x_2ndcore_code((v)+0x100000)\r
-#define gp2x_1stcore_data(v)           gp2x_1stcore_code((v)+0x100000)\r
-#define gp2x_dualcore_data(v)          gp2x_1stcore_data(v)\r
-\r
-#define gp2x_2ndcore_code_ptr(v)       ((volatile unsigned long *)(v))\r
-#define gp2x_1stcore_code_ptr(v)       (&gp2x_dualcore_ram[(v)>>2])\r
-#define gp2x_2ndcore_data_ptr(v)       gp2x_2ndcore_code_ptr((v)+0x100000)\r
-#define gp2x_1stcore_data_ptr(v)       gp2x_1stcore_code_ptr((v)+0x100000)\r
-\r
-#define gp2x_video_wait_vsync()        while(gp2x_memregs[0x1182>>1]&(1<<4));\r
-#define gp2x_video_wait_hsync()        while(gp2x_memregs[0x1182>>1]&(1<<5));\r
-\r
-#define gp2x_video_color8(C,R,G,B)     do gp2x_palette[((C)<<1)+0]=((G)<<8)|(B),gp2x_palette[((C)<<1)+1]=(R); while(0)\r
-#define gp2x_video_color15(R,G,B,A)    ((((R)&0xF8)<<8)|(((G)&0xF8)<<3)|(((B)&0xF8)>>3)|((A)<<5))\r
-\r
-\r
-extern volatile unsigned short  gp2x_palette[512];\r
-extern          unsigned short *gp2x_screen15;\r
-extern          unsigned char  *gp2x_screen8;\r
-extern volatile unsigned long  *gp2x_dualcore_ram;\r
-\r
-extern void             gp2x_init(int tickspersecond, int bpp, int rate, int bits, int stereo, int hz);\r
-extern void             gp2x_deinit(void);\r
-\r
-extern void             gp2x_video_flip(void);\r
-extern void             gp2x_video_flip_single(void);\r
-extern void             gp2x_video_setpalette(void);\r
-\r
-extern unsigned long    gp2x_joystick_read(void);\r
-\r
-extern void             gp2x_sound_volume(int left, int right);\r
-\r
-extern unsigned long    gp2x_timer_read(void);\r
-extern unsigned long    gp2x_timer_read_ms(void);\r
-\r
-extern void             gp2x_dualcore_enable(int on);\r
-extern void             gp2x_dualcore_sync(void);\r
-extern void             gp2x_dualcore_exec(unsigned long command);\r
-extern void             gp2x_dualcore_launch_program(unsigned long *area, unsigned long size);\r
-extern void             gp2x_dualcore_launch_program_from_disk(const char *file, unsigned long offset, unsigned long size);\r
-\r
-#define gp2x_dualcore_declare_subprogram(name) extern void gp2x_dualcore_launch_## name ##_subprogram(void);\r
-#define gp2x_dualcore_launch_subprogram(name)  gp2x_dualcore_launch_## name ##_subprogram()\r
+        GP2X_VOL_UP=1<<23, GP2X_VOL_DOWN=1<<22, GP2X_PUSH=1<<27 };\r
 \r
 #endif\r
 \r
 #endif\r
-\r
diff --git a/drivers/gp2x/minimal_940t.h b/drivers/gp2x/minimal_940t.h
deleted file mode 100644 (file)
index 82cd1c0..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*\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
-#include "minimal.h"\r
-\r
-#ifndef __MINIMAL_H_STUB_940T__\r
-#define __MINIMAL_H_STUB_940T__\r
-\r
-#undef    gp2x_dualcore_data\r
-#define   gp2x_dualcore_data(v)         gp2x_2ndcore_data(v)\r
-\r
-#define   main                          gp2x_2ndcore_run\r
-\r
-static void gp2x_2ndcore_start(void) __attribute__((naked));\r
-\r
-static void gp2x_2ndcore_start(void)\r
-{\r
-  unsigned long gp2x_dequeue(gp2x_queue *q)\r
-  {\r
-   unsigned long data;\r
-\r
-   while(!q->items); //waiting for head to increase...\r
-\r
-   data=q->place940t[q->tail = (q->tail < q->max_items ? q->tail+1 : 0)];\r
-   q->items--;\r
-\r
-   return data;\r
-  }\r
-\r
-#define gp2x_dualcore_name_subprogram(name) \\r
-/* 00000020 <_start>:                                                                             */ \\r
-/*    0:*/   asm volatile (".word 0xe59ff02c");  /*        ldr     pc, [pc, #44]  ; 34 <ioffset>  */ \\r
-/*    4:*/   asm volatile (".word 0xe59ff028");  /*        ldr     pc, [pc, #40]  ; 34 <ioffset>  */ \\r
-/*    8:*/   asm volatile (".word 0xe59ff024");  /*        ldr     pc, [pc, #36]  ; 34 <ioffset>  */ \\r
-/*    c:*/   asm volatile (".word 0xe59ff020");  /*        ldr     pc, [pc, #32]  ; 34 <ioffset>  */ \\r
-/*   10:*/   asm volatile (".word 0xe59ff01c");  /*        ldr     pc, [pc, #28]  ; 34 <ioffset>  */ \\r
-/*   14:*/   asm volatile (".word 0xe59ff018");  /*        ldr     pc, [pc, #24]  ; 34 <ioffset>  */ \\r
-/*   18:*/   asm volatile (".word 0xe59ff014");  /*        ldr     pc, [pc, #20]  ; 34 <ioffset>  */ \\r
-/*   1c:*/   asm volatile (".word 0xe59ff010");  /*        ldr     pc, [pc, #16]  ; 34 <ioffset>  */ \\r
-/* 00000020 <_init>:                                                                              */ \\r
-/*   20:*/   asm volatile (".word 0xe59fd010");  /*        ldr     sp, [pc, #16]   ; 38 <stack>         */ \\r
-/*   24:*/   asm volatile (".word 0xe59fc010");  /*        ldr     ip, [pc, #16]   ; 3c <deadbeef>      */ \\r
-/*   28:*/   asm volatile (".word 0xe59fb010");  /*        ldr     fp, [pc, #16]   ; 40 <leetface>      */ \\r
-/*   2c:*/   asm volatile (".word 0xe92d1800");  /*        stmdb   sp!, {fp, ip}                        */ \\r
-/*   30:*/   asm volatile (".word 0xea000004");  /*        b       48 <realinit>                        */ \\r
-/* 00000034 <ioffset>:                                                                                  */ \\r
-/*   34:*/   asm volatile (".word 0x00000020");  /*                                                     */ \\r
-/* 00000038 <stack>:                                                                                    */ \\r
-/*   38:*/   asm volatile (".word 0x000ffffc");  /*                                                     */ \\r
-/* 0000003c <deadbeef>:                                                                                 */ \\r
-/*   3c:*/   asm volatile (".word 0xdeadbeef");  /*                                                     */ \\r
-/* 00000040 <leetface>:                                                                                 */ \\r
-/*   40:*/   asm volatile (".word 0x1ee7face");  /*                                                     */ \\r
-/* 00000044 <area1>:                                                                                    */ \\r
-/*   44:*/   asm volatile (".word 0x00100019");  /*                                                     */ \\r
-/* 00000048 <realinit>:                                                                                 */ \\r
-/*  our main code starts here... */ \\r
-/*  48:*/   asm volatile (".word 0xe3a0003f"); /*        mov     r0, #63 ; 0x3f */ \\r
-/*  4c:*/   asm volatile (".word 0xee060f10"); /*        mcr     15, 0, r0, cr6, cr0, {0} */ \\r
-/*  50:*/   asm volatile (".word 0xee060f30"); /*        mcr     15, 0, r0, cr6, cr0, {1} */ \\r
-/*  54:*/   asm volatile (".word 0xe51f0018"); /*        ldr     r0, [pc, #-24]  ; 44 <area1> */ \\r
-/*  58:*/   asm volatile (".word 0xee060f11"); /*        mcr     15, 0, r0, cr6, cr1, {0} */ \\r
-/*  5c:*/   asm volatile (".word 0xee060f31"); /*        mcr     15, 0, r0, cr6, cr1, {1} */ \\r
-/*  60:*/   asm volatile (".word 0xe3a00001"); /*        mov     r0, #1  ; 0x1            */ \\r
-/*  64:*/   asm volatile (".word 0xee020f10"); /*        mcr     15, 0, r0, cr2, cr0, {0} */ \\r
-/*  68:*/   asm volatile (".word 0xee020f30"); /*        mcr     15, 0, r0, cr2, cr0, {1} */ \\r
-/*  6c:*/   asm volatile (".word 0xee030f10"); /*        mcr     15, 0, r0, cr3, cr0, {0} */ \\r
-/*  70:*/   asm volatile (".word 0xe3a0000f"); /*        mov     r0, #15 ; 0xf            */ \\r
-/*  74:*/   asm volatile (".word 0xee050f10"); /*        mcr     15, 0, r0, cr5, cr0, {0} */ \\r
-/*  78:*/   asm volatile (".word 0xee050f30"); /*        mcr     15, 0, r0, cr5, cr0, {1} */ \\r
-/*  7c:*/   asm volatile (".word 0xee110f10"); /*        mrc     15, 0, r0, cr1, cr0, {0} */ \\r
-/*  80:*/   asm volatile (".word 0xe3800001"); /*        orr     r0, r0, #1      ; 0x1    */ \\r
-/*  84:*/   asm volatile (".word 0xe3800004"); /*        orr     r0, r0, #4      ; 0x4    */ \\r
-/*  88:*/   asm volatile (".word 0xe3800a01"); /*        orr     r0, r0, #4096   ; 0x1000 */ \\r
-/*  8c:*/   asm volatile (".word 0xe3800103"); /*        orr     r0, r0, #-1073741824    ; 0xc0000000 */ \\r
-/*  90:*/   asm volatile (".word 0xee010f10"); /*        mcr     15, 0, r0, cr1, cr0, {0} */ \\r
-   while(1) gp2x_2ndcore_run(gp2x_dequeue((gp2x_queue *)gp2x_2ndcore_data_ptr(GP2X_QUEUE_ARRAY_PTR))); \\r
-} \\r
-void gp2x_dualcore_launch_##name##_subprogram(void) { gp2x_dualcore_launch_program((unsigned long *)&gp2x_2ndcore_start, ((int)&gp2x_dualcore_launch_##name##_subprogram)-((int)&gp2x_2ndcore_start)); }\r
-\r
-#endif\r
-\r
-\r
index e70bbd3..b6b628c 100644 (file)
@@ -1,5 +1,6 @@
 #include <sys/time.h>
 #include "main.h"
 #include <sys/time.h>
 #include "main.h"
+#include "gp2x.h"
 #include "throttle.h"
 
 #if 0
 #include "throttle.h"
 
 #if 0
@@ -48,7 +49,7 @@ INLINE void SpeedThrottle(void)
 #else
 
 extern uint8 PAL;
 #else
 
 extern uint8 PAL;
-extern int FSkip, FSkip_setting;
+extern int FSkip;
 static int usec_aim = 0, usec_done = 0;
 static int skip_count = 0;
 
 static int usec_aim = 0, usec_done = 0;
 static int skip_count = 0;
 
@@ -73,9 +74,9 @@ INLINE void SpeedThrottle(void)
        usec_done += tv_now.tv_usec - tv_prev.tv_usec;
 
 #ifdef FRAMESKIP
        usec_done += tv_now.tv_usec - tv_prev.tv_usec;
 
 #ifdef FRAMESKIP
-       if (FSkip_setting >= 0)
+       if (Settings.frameskip >= 0)
        {
        {
-               if (skip_count >= FSkip_setting)
+               if (skip_count >= Settings.frameskip)
                        skip_count = 0;
                else {
                        skip_count++;
                        skip_count = 0;
                else {
                        skip_count++;
@@ -85,9 +86,10 @@ INLINE void SpeedThrottle(void)
        else if (usec_done > usec_aim + 1024*4)
        {
                /* auto frameskip */
        else if (usec_done > usec_aim + 1024*4)
        {
                /* auto frameskip */
-               if (usec_done - usec_aim > 150000)
+               if (usec_done - usec_aim > 1024*32)
                        usec_done = usec_aim = 1; // too much behind, try to recover..
                        usec_done = usec_aim = 1; // too much behind, try to recover..
-               FSkip = 1;
+               else
+                       FSkip = 1;
                tv_prev = tv_now;
                return;
        }
                tv_prev = tv_now;
                return;
        }
diff --git a/drivers/gp2x/usbjoy.c b/drivers/gp2x/usbjoy.c
new file mode 100644 (file)
index 0000000..de1178a
--- /dev/null
@@ -0,0 +1,424 @@
+/* Title: USB Joystick library
+   Version 0.2
+   Written by Puck2099 (puck2099@gmail.com), (c) 2006.
+   <http://www.gp32wip.com>
+
+   If you use this library or a part of it, please, let it know.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include <stdlib.h>
+#include <stdio.h>             /* For the definition of NULL */
+#include <sys/types.h>         // For Device open
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>            // For Device read
+
+#include <string.h>
+#include <limits.h>            /* For the definition of PATH_MAX */
+#include <linux/joystick.h>
+
+#include "usbjoy.h"
+
+
+/*
+  Function: joy_open
+
+  Opens a USB joystick and fills its information.
+
+  Parameters:
+
+  joynumber - Joystick's identifier (0 reserved for GP2X's builtin Joystick).
+
+  Returns:
+
+  Filled usbjoy structure.
+
+*/
+struct usbjoy *joy_open(int joynumber)
+{
+       int fd;
+       char path [128];
+       struct usbjoy * joy = NULL;
+       struct js_event event;
+       static char insmod_done = 0;
+
+       // notaz: on my system I get unresolved input_* symbols, so have to 'insmod input' too
+       // also we should insmod only once, not on every joy_open() call.
+       if (!insmod_done) {
+               system ("insmod input");
+               system ("insmod joydev"); // Loads joydev module
+               insmod_done = 1;
+       }
+
+       if (joynumber == 0) {
+       }
+       else if (joynumber > 0) {
+               sprintf (path, "/dev/input/js%d", joynumber-1);
+               fd = open(path, O_RDONLY, 0);
+               if (fd > 0) {
+                       joy = (struct usbjoy *) malloc(sizeof(*joy));
+                       if (joy == NULL) { close(fd); return NULL; }
+                       memset(joy, 0, sizeof(*joy));
+
+                       // Set the joystick to non-blocking read mode
+                       fcntl(fd, F_SETFL, O_NONBLOCK);
+
+                       // notaz: maybe we should flush init events now.
+                       // My pad returns axis as active when I plug it in, which is kind of annoying.
+                       while (read(fd, &event, sizeof(event)) > 0);
+
+                       // Joystick's file descriptor
+                       joy->fd = fd;
+
+                       // Joystick's name
+                       ioctl(joy->fd, JSIOCGNAME(128*sizeof(char)), joy->name);
+
+                       // Joystick's device
+                       strcpy(joy->device, path);
+
+                       // Joystick's buttons
+                       ioctl(joy->fd, JSIOCGBUTTONS, &joy->numbuttons);
+
+                       // Joystick's axes
+                       ioctl(joy->fd, JSIOCGAXES, &joy->numaxes);
+
+                       // Joystick's type (derived from name)
+                       if (strncasecmp(joy->name, "logitech", strlen("logitech")) == 0)
+                            joy->type = JOY_TYPE_LOGITECH;
+                       else joy->type = JOY_TYPE_GENERIC;
+               } else {
+                       // printf ("ERROR: No Joystick found\n");
+               }
+       }
+       return joy;
+}
+
+/*
+  Function: joy_name
+
+  Returns Joystick's name.
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  Joystick's name or NULL if <usbjoy> struct is empty.
+*/
+char * joy_name (struct usbjoy * joy) {
+  if (joy != NULL)  return joy->name;
+  else return NULL;
+}
+
+
+/*
+  Function: joy_device
+
+  Returns Joystick's device.
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  Joystick's device or NULL if <usbjoy> struct is empty.
+*/
+char * joy_device (struct usbjoy * joy) {
+  if (joy != NULL)  return joy->device;
+  else return NULL;
+}
+
+
+/*
+  Function: joy_buttons
+
+  Returns Joystick's buttons number.
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  Joystick's buttons or 0 if <usbjoy> struct is empty.
+*/
+int joy_buttons (struct usbjoy * joy) {
+  if (joy != NULL) return joy->numbuttons;
+  else return 0;
+}
+
+
+/*
+  Function: joy_axes
+
+  Returns Joystick's axes number.
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  Joystick's axes or 0 if <usbjoy> struct is empty.
+*/
+int joy_axes (struct usbjoy * joy) {
+  if (joy != NULL) return joy->numaxes;
+  else return 0;
+}
+
+
+/*
+  Function: joy_update
+
+  Updates Joystick's internal information (<statebuttons> and <stateaxes> fields).
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  0 - No events registered (no need to update).
+  1 - Events registered (a button or axe has been pushed).
+  -1 - Error: <usbjoy> struct is empty.
+*/
+int joy_update (struct usbjoy * joy) {
+  struct js_event events[0xff];
+  int i, len;
+  int event = 0;
+  if (joy != NULL) {
+    if ((len=read(joy->fd, events, (sizeof events))) >0) {
+      len /= sizeof(events[0]);
+      for ( i=0; i<len; ++i ) {
+       switch (events[i].type & ~JS_EVENT_INIT) {
+       case JS_EVENT_AXIS:
+         if (events[i].number == 0) {
+           if (events[i].value == 0) joy->stateaxes[JOYLEFT] = joy->stateaxes[JOYRIGHT] = 0;
+           else if (events[i].value < 0) joy->stateaxes[JOYLEFT] = 1;
+           else joy->stateaxes[JOYRIGHT] = 1;
+         }
+         else if (events[i].number == 1) {
+           if (events[i].value == 0) joy->stateaxes[JOYUP] = joy->stateaxes[JOYDOWN] = 0;
+           else if (events[i].value < 0) joy->stateaxes[JOYUP] = 1;
+           else joy->stateaxes[JOYDOWN] = 1;
+         }
+         event = 1;
+         break;
+       case JS_EVENT_BUTTON:
+         joy->statebuttons[events[i].number] = events[i].value;
+         event = 1;
+         break;
+       default:
+         break;
+       }
+      }
+    }
+  }
+  else {
+    event = -1;
+  }
+  return event;
+}
+
+
+/*
+  Function: joy_getbutton
+
+  Returns Joystick's button information.
+
+  Parameters:
+
+  button - Button which value you want to know (from 0 to 31).
+  joy - Selected joystick.
+
+  Returns:
+
+  0 - Button NOT pushed.
+  1 - Button pushed.
+  -1 - Error: <usbjoy> struct is empty.
+*/
+int joy_getbutton (int button, struct usbjoy * joy) {
+  if (joy != NULL) {
+    if (button < joy_buttons(joy)) return joy->statebuttons[button];
+    else return 0;
+  }
+  else return -1;
+}
+
+
+/*
+  Function: joy_getaxe
+
+  Returns Joystick's axes information.
+
+  Parameters:
+
+  axe - Axe which value you want to know (see <Axes values>).
+  joy - Selected joystick.
+
+  Returns:
+
+  0 - Direction NOT pushed.
+  1 - Direction pushed.
+  -1 - Error: <usbjoy> struct is empty.
+*/
+int joy_getaxe (int axe, struct usbjoy * joy) {
+  if (joy != NULL) {
+    if (axe < 4) return joy->stateaxes[axe];
+    else return 0;
+  }
+  else return -1;
+}
+
+
+/*
+  Function: joy_close
+
+  Closes selected joystick's file descriptor and detroys it's fields.
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  0 - Joystick successfully closed.
+  -1 - Error: <usbjoy> struct is empty.
+*/
+int joy_close (struct usbjoy * joy) {
+  if (joy != NULL) {
+    close (joy->fd);
+    free (joy);
+    return 0;
+  }
+  else return -1;
+}
+
+
+/*********************************************************************/
+/* GP2X USB Joystick Handling -GnoStiC                               */
+/*********************************************************************/
+
+#include "minimal.h"
+
+int num_of_joys = 0;
+struct usbjoy *joys[4];
+
+void gp2x_usbjoy_init (void) {
+       /* Open available joysticks -GnoStiC */
+       int i, n = 0;
+
+       printf("\n");
+       for (i = 0; i < 4; i++) {
+               joys[n] = joy_open(i+1);
+               if (joys[n] && joy_buttons(joys[n]) > 0) {
+                       printf ("+-Joystick %d: \"%s\", buttons = %i\n", i+1, joy_name(joys[n]), joy_buttons(joys[n]));
+                       n++;
+               }
+       }
+       num_of_joys = n;
+
+       printf("Found %d Joystick(s)\n",num_of_joys);
+}
+
+void gp2x_usbjoy_update (void) {
+       /* Update Joystick Event Cache */
+       int q, foo;
+       for (q=0; q < num_of_joys; q++) {
+               foo = joy_update (joys[q]);
+       }
+}
+
+int gp2x_usbjoy_check (int joyno) {
+       /* Check Joystick */
+       int q, joyExKey = 0;
+       struct usbjoy *joy = joys[joyno];
+
+       if (joy != NULL) {
+               if (joy_getaxe(JOYUP, joy))    { joyExKey |= GP2X_UP; }
+               if (joy_getaxe(JOYDOWN, joy))  { joyExKey |= GP2X_DOWN; }
+               if (joy_getaxe(JOYLEFT, joy))  { joyExKey |= GP2X_LEFT; }
+               if (joy_getaxe(JOYRIGHT, joy)) { joyExKey |= GP2X_RIGHT; }
+
+               /* loop through joy buttons to check if they are pushed */
+               for (q=0; q<joy_buttons (joy); q++) {
+                       if (joy_getbutton (q, joy)) {
+                               if (joy->type == JOY_TYPE_LOGITECH) {
+                                       switch (q) {
+                                               case 0: joyExKey |= GP2X_A; break;
+                                               case 1: joyExKey |= GP2X_X; break;
+                                               case 2: joyExKey |= GP2X_B; break;
+                                               case 3: joyExKey |= GP2X_Y; break;
+                                       }
+                               } else {
+                                       switch (q) {
+                                               case 0: joyExKey |= GP2X_Y; break;
+                                               case 1: joyExKey |= GP2X_B; break;
+                                               case 2: joyExKey |= GP2X_X; break;
+                                               case 3: joyExKey |= GP2X_A; break;
+                                       }
+                               }
+
+                               switch (q) {
+                                       case  4: joyExKey |= GP2X_L; break;
+                                       case  5: joyExKey |= GP2X_R; break;
+                                       case  6: joyExKey |= GP2X_L; break; /* left shoulder button 2 */
+                                       case  7: joyExKey |= GP2X_R; break; /* right shoulder button 2 */
+                                       case  8: joyExKey |= GP2X_SELECT;break;
+                                       case  9: joyExKey |= GP2X_START; break;
+                                       case 10: joyExKey |= GP2X_PUSH;  break;
+                                       case 11: joyExKey |= GP2X_PUSH;  break;
+                               }
+                       }
+               }
+       }
+       return joyExKey;
+}
+
+int gp2x_usbjoy_check2 (int joyno) {
+       /* Check Joystick, don't map to gp2x joy */
+       int q, to, joyExKey = 0;
+       struct usbjoy *joy = joys[joyno];
+
+       if (joy != NULL) {
+               if (joy_getaxe(JOYUP, joy))    { joyExKey |= 1 << 0; }
+               if (joy_getaxe(JOYDOWN, joy))  { joyExKey |= 1 << 1; }
+               if (joy_getaxe(JOYLEFT, joy))  { joyExKey |= 1 << 2; }
+               if (joy_getaxe(JOYRIGHT, joy)) { joyExKey |= 1 << 3; }
+
+               /* loop through joy buttons to check if they are pushed */
+               to = joy->numbuttons;
+               if (to > 32-4) to = 32-4;
+               for (q=0; q < to; q++)
+                       if (joy->statebuttons[q]) joyExKey |= 1 << (q+4);
+       }
+       return joyExKey;
+}
+
+
+
+void gp2x_usbjoy_deinit (void) {
+       int i;
+       for (i=0; i<num_of_joys; i++) {
+               joy_close (joys[i]);
+       }
+       num_of_joys = 0;
+}
+
diff --git a/drivers/gp2x/usbjoy.h b/drivers/gp2x/usbjoy.h
new file mode 100644 (file)
index 0000000..3d8810a
--- /dev/null
@@ -0,0 +1,241 @@
+/* Title: USB Joystick library
+   Version 0.2
+   Written by Puck2099 (puck2099@gmail.com), (c) 2006.
+   <http://www.gp32wip.com>
+
+   If you use this library or a part of it, please, let it know.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#ifndef USBJOY_H
+#define USBJOY_H
+
+/* notaz: my Logitech has different button layout, and I want it to match gp2x's */
+typedef enum {
+       JOY_TYPE_GENERIC,
+       JOY_TYPE_LOGITECH
+} joy_type;
+
+/*
+  Enumeration: Axes values
+  This enumeration contains shortcuts to the values used on axes.
+
+  Constants:
+  JOYUP    - Joystick Up
+  JOYDOWN  - Joystick Down
+  JOYLEFT  - Joystick Left
+  JOYRIGHT - Joystick Right
+
+  See also:
+  <joy_getaxe>
+*/
+#define JOYUP    (0)
+#define JOYDOWN  (1)
+#define JOYLEFT  (2)
+#define JOYRIGHT (3)
+
+
+/*
+  Struct: usbjoy
+
+  Contains all Joystick needed information.
+
+  Fields:
+  fd - File descriptor used.
+  name - Joystick's name.
+  device - /dev/input/jsX device.
+  numbuttons - Joystick's buttons.
+  numaxes - Joystick's axes.
+  numhats - Joystick's hats.
+  statebuttons - Current state of each button.
+  stateaxes - Current state of each direction.
+*/
+struct usbjoy {
+  int fd;
+  char name [128];
+  char device [128];
+  int numbuttons;
+  int numaxes;
+  int numhats;
+  int statebuttons[32];
+  int stateaxes[4];
+  joy_type type;
+};
+
+
+/*
+  Function: joy_open
+
+  Opens a USB joystick and fills its information.
+
+  Parameters:
+
+  joynumber - Joystick's identifier (0 reserved for GP2X's builtin Joystick).
+
+  Returns:
+
+  Filled usbjoy structure.
+*/
+struct usbjoy * joy_open (int joynumber);
+
+
+/*
+  Function: joy_name
+
+  Returns Joystick's name.
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  Joystick's name or NULL if <usbjoy> struct is empty.
+*/
+char * joy_name (struct usbjoy * joy);
+
+
+/*
+  Function: joy_device
+
+  Returns Joystick's device.
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  Joystick's device or NULL if <usbjoy> struct is empty.
+*/
+char * joy_device (struct usbjoy * joy);
+
+/*
+  Function: joy_buttons
+
+  Returns Joystick's buttons number.
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  Joystick's buttons or 0 if <usbjoy> struct is empty.
+*/
+int joy_buttons (struct usbjoy * joy);
+
+/*
+  Function: joy_axes
+
+  Returns Joystick's axes number.
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  Joystick's axes or 0 if <usbjoy> struct is empty.
+*/
+int joy_axes (struct usbjoy * joy);
+
+
+/*
+  Function: joy_update
+
+  Updates Joystick's internal information (<statebuttons> and <stateaxes> fields).
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  0 - No events registered (no need to update).
+  1 - Events registered (a button or axe has been pushed).
+  -1 - Error: <usbjoy> struct is empty.
+*/
+int joy_update (struct usbjoy * joy);
+
+
+/*
+  Function: joy_getbutton
+
+  Returns Joystick's button information.
+
+  Parameters:
+
+  button - Button which value you want to know (from 0 to 31).
+  joy - Selected joystick.
+
+  Returns:
+
+  0 - Button NOT pushed.
+  1 - Button pushed.
+  -1 - Error: <usbjoy> struct is empty.
+*/
+int joy_getbutton (int button, struct usbjoy * joy);
+
+
+/*
+  Function: joy_getaxe
+
+  Returns Joystick's axes information.
+
+  Parameters:
+
+  axe - Axe which value you want to know (see <Axes values>).
+  joy - Selected joystick.
+
+  Returns:
+
+  0 - Direction NOT pushed.
+  1 - Direction pushed.
+  -1 - Error: <usbjoy> struct is empty.
+*/
+int joy_getaxe (int axe, struct usbjoy * joy);
+
+/*
+  Function: joy_close
+
+  Closes selected joystick's file descriptor and detroys it's fields.
+
+  Parameters:
+
+  joy - Selected joystick.
+
+  Returns:
+
+  0 - Joystick successfully closed.
+  -1 - Error: <usbjoy> struct is empty.
+*/
+int joy_close (struct usbjoy * joy);
+
+
+
+/* gp2x stuff */
+extern int num_of_joys;
+extern struct usbjoy *joys[4];
+
+void gp2x_usbjoy_update(void);
+void gp2x_usbjoy_init(void);
+int  gp2x_usbjoy_check(int joyno);
+int  gp2x_usbjoy_check2(int joyno);
+void gp2x_usbjoy_deinit(void);
+
+
+#endif // USBJOY_H
diff --git a/fce.c b/fce.c
index 35d7209..38680f9 100644 (file)
--- a/fce.c
+++ b/fce.c
@@ -1092,7 +1092,7 @@ FCEUGI *FCEUI_LoadGame(char *name)
        int have_movie = 0;
         int fp;
 
        int have_movie = 0;
         int fp;
 
-        Exit=1;
+        //Exit=1;
         ResetGameLoaded();
 
        strncpy(name2, name, sizeof(name2));
         ResetGameLoaded();
 
        strncpy(name2, name, sizeof(name2));
@@ -1114,6 +1114,8 @@ FCEUGI *FCEUI_LoadGame(char *name)
          FCEU_fclose(fp);
          *p = 0;
          fp=FCEU_fopen(name2,"rb");
          FCEU_fclose(fp);
          *p = 0;
          fp=FCEU_fopen(name2,"rb");
+         if (!fp && p - name2 > 2)  p[-2] = 0;
+         fp=FCEU_fopen(name2,"rb");
          if (!fp) {
           printf("no ROM for movie\n");
           return 0;
          if (!fp) {
           printf("no ROM for movie\n");
           return 0;
@@ -1356,7 +1358,7 @@ update:
 
   if(Exit)
   {
 
   if(Exit)
   {
-   CloseGame();
+   //CloseGame();
    break;
   }
 
    break;
   }