add prep tool and common
authornotaz <notaz@pixelinis>
Wed, 28 Jul 2010 13:16:21 +0000 (16:16 +0300)
committernotaz <notaz@pixelinis>
Wed, 28 Jul 2010 13:16:21 +0000 (16:16 +0300)
common/cmn.c [new file with mode: 0644]
common/cmn.h [new file with mode: 0644]
common/fbdev.c [new file with mode: 0644]
common/fbdev.h [new file with mode: 0644]
common/host_fb.c [new file with mode: 0644]
common/host_fb.h [new file with mode: 0644]
common/wiz_video.c [new file with mode: 0644]
prep/Makefile [new file with mode: 0644]
prep/font.c [new file with mode: 0644]
prep/main.c [new file with mode: 0644]

diff --git a/common/cmn.c b/common/cmn.c
new file mode 100644 (file)
index 0000000..9f802ba
--- /dev/null
@@ -0,0 +1,43 @@
+#ifdef LOADER
+#include "../loader/realfuncs.h"
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "cmn.h"
+
+int make_local_path(char *buf, size_t size, const char *file)
+{
+  ssize_t ret;
+  char *p;
+
+  ret = readlink("/proc/self/exe", buf, size - 1);
+  if (ret < 0) {
+    perror("readlink");
+    goto err;
+  }
+  buf[ret] = 0;
+
+  p = strrchr(buf, '/');
+  if (p == NULL)
+    goto err;
+  p++;
+
+  if (strstr(p, ".so")) {
+    p = getenv("GINGE_ROOT");
+    if (p == NULL)
+      goto err;
+    strcpy(buf, p);
+    p = buf + strlen(buf);
+  }
+
+  snprintf(p, size - (p - buf), "%s", file);
+
+  return 0;
+
+err:
+  fprintf(stderr, "ginge: can't determine root, buf: \"%s\"\n", buf);
+  return -1;
+}
+
diff --git a/common/cmn.h b/common/cmn.h
new file mode 100644 (file)
index 0000000..9257e11
--- /dev/null
@@ -0,0 +1,3 @@
+#include <stdlib.h>
+
+int make_local_path(char *buf, size_t size, const char *file);
diff --git a/common/fbdev.c b/common/fbdev.c
new file mode 100644 (file)
index 0000000..069dc6e
--- /dev/null
@@ -0,0 +1,180 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <linux/fb.h>
+#include <linux/matroxfb.h>
+
+#include "fbdev.h"
+
+#define FBDEV_MAX_BUFFERS 3
+
+struct vout_fbdev {
+       int     fd;
+       void    *mem;
+       size_t  mem_size;
+       struct  fb_var_screeninfo fbvar_old;
+       struct  fb_var_screeninfo fbvar_new;
+       int     buffer_write;
+       void    *buffers[FBDEV_MAX_BUFFERS];
+       int     buffer_count;
+};
+
+void *vout_fbdev_flip(struct vout_fbdev *fbdev)
+{
+       int draw_buf;
+
+       if (fbdev->buffer_count < 2)
+               return fbdev->mem;
+
+       draw_buf = fbdev->buffer_write;
+       fbdev->buffer_write++;
+       if (fbdev->buffer_write >= fbdev->buffer_count)
+               fbdev->buffer_write = 0;
+
+       fbdev->fbvar_new.yoffset = fbdev->fbvar_old.yres * draw_buf;
+
+       ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new);
+
+       return fbdev->buffers[fbdev->buffer_write];
+}
+
+void vout_fbdev_wait_vsync(struct vout_fbdev *fbdev)
+{
+       int arg = 0;
+       ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &arg);
+}
+
+void vout_fbdev_clear(struct vout_fbdev *fbdev)
+{
+       memset(fbdev->mem, 0, fbdev->mem_size);
+}
+
+struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int no_dblbuf)
+{
+       struct vout_fbdev *fbdev;
+       int i, ret;
+
+       fbdev = calloc(1, sizeof(*fbdev));
+       if (fbdev == NULL)
+               return NULL;
+
+       fbdev->fd = open(fbdev_name, O_RDWR, 0);
+       if (fbdev->fd == -1) {
+               fprintf(stderr, "%s: ", fbdev_name);
+               perror("open");
+               goto fail_open;
+       }
+
+       ret = ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->fbvar_old);
+       if (ret == -1) {
+               perror("FBIOGET_VSCREENINFO ioctl");
+               goto fail;
+       }
+
+       fbdev->fbvar_new = fbdev->fbvar_old;
+       printf("%s: %ix%i@%d\n", fbdev_name, fbdev->fbvar_old.xres, fbdev->fbvar_old.yres,
+               fbdev->fbvar_old.bits_per_pixel);
+       *w = fbdev->fbvar_old.xres;
+       *h = fbdev->fbvar_old.yres;
+       fbdev->buffer_count = FBDEV_MAX_BUFFERS; // be optimistic
+       if (no_dblbuf)
+               fbdev->buffer_count = 1;
+
+       if (fbdev->fbvar_new.bits_per_pixel != 16) {
+               printf(" switching to 16bpp\n");
+               fbdev->fbvar_new.bits_per_pixel = 16;
+               ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
+               if (ret == -1) {
+                       perror("FBIOPUT_VSCREENINFO ioctl");
+                       goto fail;
+               }
+       }
+
+       if (fbdev->fbvar_new.yres_virtual < fbdev->fbvar_old.yres * fbdev->buffer_count) {
+               fbdev->fbvar_new.yres_virtual = fbdev->fbvar_old.yres * fbdev->buffer_count;
+               ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
+               if (ret == -1) {
+                       fbdev->buffer_count = 1;
+                       fprintf(stderr, "Warning: failed to increase virtual resolution, "
+                                       "doublebuffering disabled\n");
+               }
+       }
+
+       fbdev->mem_size = *w * *h * 2 * fbdev->buffer_count;
+       fbdev->mem = mmap(0, fbdev->mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
+       if (fbdev->mem == MAP_FAILED && fbdev->buffer_count > 1) {
+               fprintf(stderr, "Warning: can't map %zd bytes, doublebuffering disabled\n", fbdev->mem_size);
+               fbdev->mem_size = *w * *h * 2;
+               fbdev->buffer_count = 1;
+               fbdev->mem = mmap(0, fbdev->mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
+       }
+       if (fbdev->mem == MAP_FAILED) {
+               perror("mmap framebuffer");
+               goto fail;
+       }
+       memset(fbdev->mem, 0, fbdev->mem_size);
+       for (i = 0; i < fbdev->buffer_count; i++)
+               fbdev->buffers[i] = (char *)fbdev->mem + i * *w * *h * 2;
+
+       // some checks
+       ret = 0;
+       ret = ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &ret);
+       if (ret != 0)
+               fprintf(stderr, "Warning: vsync doesn't seem to be supported\n");
+
+       if (fbdev->buffer_count > 1) {
+               fbdev->buffer_write = 0;
+               fbdev->fbvar_new.yoffset = fbdev->fbvar_old.yres * (fbdev->buffer_count - 1);
+               ret = ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new);
+               if (ret != 0) {
+                       fbdev->buffer_count = 1;
+                       fprintf(stderr, "Warning: can't pan display, doublebuffering disabled\n");
+               }
+       }
+
+       printf("fbdev initialized.\n");
+       return fbdev;
+
+fail:
+       close(fbdev->fd);
+fail_open:
+       free(fbdev);
+       return NULL;
+}
+
+void vout_fbdev_finish(struct vout_fbdev *fbdev)
+{
+       ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_old);
+       if (fbdev->mem != MAP_FAILED)
+               munmap(fbdev->mem, fbdev->mem_size);
+       if (fbdev->fd >= 0)
+               close(fbdev->fd);
+       fbdev->mem = NULL;
+       fbdev->fd = -1;
+       free(fbdev);
+}
+
+#if 0
+void *g_screen_ptr;
+int main()
+{
+       int w, h;
+       vout_fbdev_init(&w, &h);
+       //while (1)
+       {
+               memset(g_screen_ptr, 0xff, fbdev_mem_size / 2);
+               plat_video_wait_vsync();
+               plat_video_flip();
+               memset(g_screen_ptr, 0x00, fbdev_mem_size / 2);
+               usleep(8000);
+//             plat_video_wait_vsync();
+               plat_video_flip();
+       }
+}
+#endif
diff --git a/common/fbdev.h b/common/fbdev.h
new file mode 100644 (file)
index 0000000..9e5d433
--- /dev/null
@@ -0,0 +1,7 @@
+struct vout_fbdev;
+
+struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int no_dblbuf);
+void *vout_fbdev_flip(struct vout_fbdev *fbdev);
+void  vout_fbdev_wait_vsync(struct vout_fbdev *fbdev);
+void  vout_fbdev_clear(struct vout_fbdev *fbdev);
+void  vout_fbdev_finish(struct vout_fbdev *fbdev);
diff --git a/common/host_fb.c b/common/host_fb.c
new file mode 100644 (file)
index 0000000..92cde57
--- /dev/null
@@ -0,0 +1,27 @@
+#ifdef LOADER
+#include "../loader/realfuncs.h"
+#endif
+
+#include "fbdev.c"
+#include "host_fb.h"
+
+static struct vout_fbdev *fbdev;
+
+int host_video_init(int *stride, int no_dblbuf)
+{
+       const char *fbdev_name;
+       int w, h;
+
+       fbdev_name = getenv("FBDEV");
+       if (fbdev_name == NULL)
+               fbdev_name = "/dev/fb1";
+       
+       fbdev = vout_fbdev_init(fbdev_name, &w, &h, no_dblbuf);
+       *stride = w * 2;
+       return (fbdev != 0) ? 0 : -1;
+}
+
+void *host_video_flip(void)
+{
+       return vout_fbdev_flip(fbdev);
+}
diff --git a/common/host_fb.h b/common/host_fb.h
new file mode 100644 (file)
index 0000000..bd739d4
--- /dev/null
@@ -0,0 +1,3 @@
+int   host_video_init(int *stride, int no_dblbuf);
+void *host_video_flip(void);
+
diff --git a/common/wiz_video.c b/common/wiz_video.c
new file mode 100644 (file)
index 0000000..4395683
--- /dev/null
@@ -0,0 +1,100 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <linux/fb.h>
+
+static volatile unsigned short *memregs;
+static volatile unsigned long  *memregl;
+static int memdev = -1;
+
+#define FB_BUF_COUNT 4
+static unsigned int fb_paddr[FB_BUF_COUNT];
+static int fb_work_buf;
+static int fbdev = -1;
+
+static void *gp2x_screens[FB_BUF_COUNT];
+static void *g_screen_ptr;
+
+
+static void vout_gp2x_flip(void)
+{
+       memregl[0x406C>>2] = fb_paddr[fb_work_buf];
+       memregl[0x4058>>2] |= 0x10;
+
+       fb_work_buf++;
+       if (fb_work_buf >= FB_BUF_COUNT)
+               fb_work_buf = 0;
+       g_screen_ptr = gp2x_screens[fb_work_buf];
+}
+
+static int vout_gp2x_init(void)
+{
+       struct fb_fix_screeninfo fbfix;
+       int i, ret;
+
+       memdev = open("/dev/mem", O_RDWR);
+       if (memdev == -1) {
+               perror("open(/dev/mem) failed");
+               exit(1);
+       }
+
+       memregs = mmap(0, 0x20000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
+       if (memregs == MAP_FAILED) {
+               perror("mmap(memregs) failed");
+               exit(1);
+       }
+       memregl = (volatile void *)memregs;
+
+       fbdev = open("/dev/fb0", O_RDWR);
+       if (fbdev < 0) {
+               perror("can't open fbdev");
+               exit(1);
+       }
+
+       ret = ioctl(fbdev, FBIOGET_FSCREENINFO, &fbfix);
+       if (ret == -1) {
+               perror("ioctl(fbdev) failed");
+               exit(1);
+       }
+
+       printf("framebuffer: \"%s\" @ %08lx\n", fbfix.id, fbfix.smem_start);
+       fb_paddr[0] = fbfix.smem_start;
+
+       gp2x_screens[0] = mmap(0, 320*240*2*FB_BUF_COUNT, PROT_READ|PROT_WRITE,
+                       MAP_SHARED, memdev, fb_paddr[0]);
+       if (gp2x_screens[0] == MAP_FAILED)
+       {
+               perror("mmap(gp2x_screens) failed");
+               exit(1);
+       }
+       memset(gp2x_screens[0], 0, 320*240*2*FB_BUF_COUNT);
+
+       printf("  %p -> %08x\n", gp2x_screens[0], fb_paddr[0]);
+       for (i = 1; i < FB_BUF_COUNT; i++)
+       {
+               fb_paddr[i] = fb_paddr[i-1] + 320*240*2;
+               gp2x_screens[i] = (char *)gp2x_screens[i-1] + 320*240*2;
+               printf("  %p -> %08x\n", gp2x_screens[i], fb_paddr[i]);
+       }
+       fb_work_buf = 0;
+       g_screen_ptr = gp2x_screens[0];
+
+       return 0;
+}
+
+void vout_gp2x_finish(void)
+{
+       memregl[0x406C>>2] = fb_paddr[0];
+       memregl[0x4058>>2] |= 0x10;
+       close(fbdev);
+
+       munmap((void *)memregs, 0x20000);
+       close(memdev);
+}
+
diff --git a/prep/Makefile b/prep/Makefile
new file mode 100644 (file)
index 0000000..368dc0e
--- /dev/null
@@ -0,0 +1,16 @@
+CC = $(CROSS_COMPILE)gcc
+CFLAGS += -Wall -O2
+LDFLAGS = -s -O2
+
+vpath %.c = ../common/
+
+TARGET = ginge_prep
+OBJS = main.o host_fb.o cmn.o
+
+all: $(TARGET)
+
+ginge_prep: $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       $(RM) $(TARGET) $(OBJS)
diff --git a/prep/font.c b/prep/font.c
new file mode 100644 (file)
index 0000000..bc1f764
--- /dev/null
@@ -0,0 +1,68 @@
+static const 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,
+};
+
diff --git a/prep/main.c b/prep/main.c
new file mode 100644 (file)
index 0000000..7cc4337
--- /dev/null
@@ -0,0 +1,427 @@
+// vim:shiftwidth=2:expandtab
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <elf.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#include "../common/host_fb.h"
+#include "../common/cmn.h"
+
+#define PFX "ging_prep: "
+#define LOADER_STATIC   "ginge_sloader"
+#define LOADER_DYNAMIC  "ginge_dyn.sh"
+#define LAUNCHER        "gp2xmenu"
+
+#include "font.c"
+
+static void *fb_mem;
+static int fb_stride;
+static int fb_x, fb_y;
+
+static char *sskip(char *p)
+{
+  while (p && *p && isspace(*p))
+    p++;
+  return p;
+}
+
+static char *cskip(char *p)
+{
+  while (p && *p && !isspace(*p))
+    p++;
+  return p;
+}
+
+static void fb_syms_out(void *fbi, int x, int y, int dotsz, int stride, const char *text, int count)
+{
+  int v = -1, n = 0, *p;
+  int i, l;
+  char *fb;
+
+  fb = (char *)fbi + x * dotsz + y * stride;
+
+  for (i = 0; i < count; i++)
+  {
+    for (l = 0; l < 8; l++)
+    {
+      #define pix(fdmask,add) \
+        p = (fontdata8x8[((text[i])*8)+l] & fdmask) ? &v : &n; \
+        memcpy(fb + l*stride + add*dotsz, p, dotsz)
+      pix(0x80,  0);
+      pix(0x40,  1);
+      pix(0x20,  2);
+      pix(0x10,  3);
+      pix(0x08,  4);
+      pix(0x04,  5);
+      pix(0x02,  6);
+      pix(0x01,  7);
+      #undef pix
+    }
+    fb += dotsz * 8;
+  }
+}
+
+// FIXME: y overrun
+static void fb_text_out(char *text)
+{
+  int dotsz = 2, w = 320; // hardcoded for now
+  char *p, *pe;
+  int l;
+
+  if (fb_mem == NULL)
+    return;
+
+  p = text;
+  while (*p) {
+    for (; *p && isspace(*p); p++) {
+      if (*p == '\n' || fb_x + dotsz * 8 > w) {
+        fb_x = 4;
+        fb_y += 8;
+      }
+      if (*p >= 0x20)
+        fb_x += 8;
+    }
+
+    pe = cskip(p);
+    l = pe - p;
+    if (fb_x + 8 * l > w) {
+      fb_x = 4;
+      fb_y += 8;
+    }
+    fb_syms_out(fb_mem, fb_x, fb_y, dotsz, fb_stride, p, l);
+    fb_x += 8 * l;
+    p = pe;
+  }
+}
+
+static void fb_text_init(void)
+{
+  int ret = host_video_init(&fb_stride, 1);
+  if (ret == 0)
+    fb_mem = host_video_flip();
+  fb_x = 4;
+  fb_y = 4;
+}
+
+static void fbprintf(int is_err, const char *format, ...)
+{
+  va_list ap;
+  char buff[512];
+
+  va_start(ap, format);
+  vsnprintf(buff, sizeof(buff), format, ap);
+  va_end(ap);
+  fputs(buff, is_err ? stderr : stdout);
+
+  fb_text_out(buff);
+}
+
+#define msg(fmt, ...) fbprintf(0, fmt, #__VA_ARGS__)
+#define err(fmt, ...) fbprintf(1, fmt, #__VA_ARGS__)
+
+static int id_elf(const char *fname)
+{
+  Elf32_Ehdr hdr;
+  Elf32_Phdr *phdr = NULL;
+  FILE *fi;
+  int i, ret = 0;
+
+  fi = fopen(fname, "rb");
+  if (fi == NULL) {
+    err("open %s: ", fname);
+    perror("");
+    return -1;
+  }
+
+  if (fread(&hdr, 1, sizeof(hdr), fi) != sizeof(hdr))
+    goto out;
+
+  if (memcmp(hdr.e_ident, ELFMAG "\x01\x01", SELFMAG + 2) != 0)
+    goto out;
+
+  if (hdr.e_phentsize != sizeof(Elf32_Phdr) || hdr.e_phnum == 0)
+    goto out;
+
+  phdr = malloc(hdr.e_phnum * hdr.e_phentsize);
+  if (phdr == NULL)
+    goto out;
+
+  if (fread(phdr, hdr.e_phentsize, hdr.e_phnum, fi) != hdr.e_phnum)
+    goto out;
+
+  ret = 1;
+
+  // do what 'file' does - check for PT_INTERP in program headers
+  for (i = 0; i < hdr.e_phnum; i++) {
+    if (phdr[i].p_type == PT_INTERP) {
+      ret = 2;
+      break;
+    }
+  }
+
+out:
+  fclose(fi);
+  free(phdr);
+  return ret;
+}
+
+static void dump_args(FILE *fout, int argc, char * const argv[])
+{
+  const char *p;
+  int i;
+
+  for (i = 0; i < argc; i++) {
+    if (i != 0)
+      fputc(' ', fout);
+    fputc('"', fout);
+
+    for (p = argv[i]; *p != 0; p++) {
+      if (*p == '"')
+        fputc('\\', fout);
+      fputc(*p, fout);
+    }
+
+    fputc('"', fout);
+  }
+}
+
+static char *get_arg(char *d, size_t size, char *p)
+{
+  char *pe;
+  int len;
+
+  p = sskip(p);
+  pe = cskip(p);
+  len = pe - p;
+
+  if (len > size - 1) {
+    err(PFX "get_arg: buff to small: %d/%d\n", len, size);
+    len = size - 1;
+  }
+  strncpy(d, p, len);
+  d[len] = 0;
+
+  return sskip(pe);
+}
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+#define CB_ENTRY(x) { x, sizeof(x) - 1 }
+const struct {
+  const char *name;
+  int len;
+} conv_blacklist[] = {
+  CB_ENTRY("insmod"),
+  CB_ENTRY("modprobe"),
+  CB_ENTRY("umount"),
+  CB_ENTRY("./cpuctrl_tiny"),
+};
+
+static int cmd_in_blacklist(char *cmd)
+{
+  int i;
+
+  cmd = sskip(cmd);
+  for (i = 0; i < ARRAY_SIZE(conv_blacklist); i++)
+    if (strncmp(cmd, conv_blacklist[i].name, conv_blacklist[i].len) == 0)
+      return 1;
+
+  return 0;
+}
+
+int main(int argc, char *argv[])
+{
+  static const char out_script[] = "/tmp/ginge_conv.sh";
+  char root_path[512], cwd[512];
+  int have_cramfs = 0;
+  int rerun_gp2xmenu = 1;
+  FILE *fin, *fout;
+  int ret;
+
+  fb_text_init();
+
+  if (argc < 2) {
+    err("usage: %s <script|program> [args]\n", argv[0]);
+    return 1;
+  }
+
+  if (getcwd(cwd, sizeof(cwd)) == NULL) {
+    err(PFX "failed to get cwd\n");
+    return 1;
+  }
+
+  ret = make_local_path(root_path, sizeof(root_path), "");
+  if (ret != 0) {
+    err(PFX "failed to generate root path\n");
+    return 1;
+  }
+
+  fout = fopen(out_script, "w");
+  if (fout == NULL) {
+    perror("can't open output script");
+    return 1;
+  }
+
+  fprintf(fout, "#!/bin/sh\n");
+
+  ret = id_elf(argv[1]);
+  if (ret == 1 || ret == 2) {
+    if (cmd_in_blacklist(argv[1])) {
+      fprintf(stderr, "blacklisted: %s\n", argv[1]);
+      goto no_in_script;
+    }
+  }
+
+  switch (ret) {
+  case 0:
+    break;
+
+  case 1:
+    fprintf(fout, "op_runfbapp %s%s ", root_path, LOADER_STATIC);
+    dump_args(fout, argc - 1, &argv[1]);
+    fprintf(fout, "\n");
+    goto no_in_script;
+
+  case 2:
+    fprintf(fout, "op_runfbapp %s%s \"%s\" ", root_path, LOADER_DYNAMIC, root_path);
+    dump_args(fout, argc - 1, &argv[1]);
+    fprintf(fout, "\n");
+    goto no_in_script;
+
+  default:
+    return 1;
+  }
+
+  // assume script
+  fin = fopen(argv[1], "r");
+  if (fin == NULL)
+    return 1;
+
+  while (1) {
+    char buff[512], fname[512], *p, *p2;
+
+    p = fgets(buff, sizeof(buff), fin);
+    if (p == NULL)
+      break;
+    p = sskip(p);
+
+    if (p[0] == '#' && p[1] == '!')
+      continue;
+
+    if (*p == 0) {
+      fputs("\n", fout);
+      continue;
+    }
+
+    // things we are sure we want to pass
+    if (*p == '#' || strncmp(p, "export ", 7) == 0)
+      goto pass;
+
+    // hmh..
+    if (strncmp(p, "exec ", 5) == 0)
+      p = sskip(p + 5);
+
+    // blacklist some stuff
+    if      (strncmp(p, "/sbin/", 6) == 0)
+      p2 = p + 6;
+    else if (strncmp(p, "/bin/", 5) == 0)
+      p2 = p + 5;
+    else
+      p2 = p;
+    if (strncmp(p2, "mount ", 6) == 0) {
+      p2 = sskip(p2 + 6);
+      // cramfs stuff?
+      if (strstr(p2, "cramfs")) {
+        while (*p2 == '-') {
+          // skip option
+          p2 = sskip(cskip(p2));
+          p2 = sskip(cskip(p2));
+        }
+        if (*p2 == 0) {
+          err(PFX "cramfs: missing mount file in \"%s\"?\n", p);
+          continue;
+        }
+        p2 = get_arg(fname, sizeof(fname), p2);
+        if (*p2 == 0) {
+          err(PFX "cramfs: missing mount point in \"%s\"?\n", p);
+          continue;
+        }
+        get_arg(buff, sizeof(buff), p2);
+        fprintf(fout, "if [ `ls %s | wc -l` -eq 0 ]; then\n", buff);
+        fprintf(fout, "  rmdir \"%s\"\n", buff); // cramfsck doesn't want it
+        fprintf(fout, "  %stools/cramfsck -x \"%s\" \"%s\"\n", root_path, buff, fname);
+        fprintf(fout, "fi\n");
+        have_cramfs = 1;
+      }
+      continue;
+    }
+    if (cmd_in_blacklist(p2))
+      continue;
+
+    // cd?
+    if (strncmp(p, "cd ", 3) == 0) {
+      get_arg(fname, sizeof(fname), p + 3);
+      if (strncmp(fname, "/usr/gp2x", 9) == 0)
+        continue;
+      ret = chdir(fname);
+      if (ret != 0) {
+        err("%s: ", fname);
+        perror("");
+      }
+    }
+
+    // trying to run something from cwd?
+    if ((p[0] == '.' && p[1] == '/') || *p == '/') {
+      get_arg(fname, sizeof(fname), p);
+      p2 = strrchr(fname, '/');
+      if (p2 != NULL && strcmp(p2 + 1, "gp2xmenu") == 0)
+        continue;
+
+      ret = id_elf(fname);
+      switch (ret) {
+      case 1:
+        printf(PFX "prefixing as static: %s", p);
+        fprintf(fout, "op_runfbapp %s%s ", root_path, LOADER_STATIC);
+        break;
+
+      case 2:
+        printf(PFX "prefixing as dynamic: %s", p);
+        fprintf(fout, "op_runfbapp %s%s \"%s\" ", root_path, LOADER_DYNAMIC, root_path);
+        break;
+
+      default:
+        break;
+      }
+    }
+
+pass:
+    fputs(p, fout);
+  }
+
+  fclose(fin);
+
+no_in_script:
+  if (rerun_gp2xmenu) {
+    fprintf(fout, "cd %s\n", root_path);
+    fprintf(fout, "exec %s%s\n", root_path, LAUNCHER);
+  }
+
+  fclose(fout);
+
+  msg("starting script..\n");
+  if (have_cramfs)
+    msg("\nsome files need to be unpacked, this may tike a few minutes.\n"
+        "Please wait at least while SD LED is active.\n");
+  system("echo ---; cat /tmp/ginge_conv.sh; echo ---");
+  chmod(out_script, S_IRWXU|S_IRWXG|S_IRWXO);
+  chdir(cwd);
+  execlp(out_script, out_script, NULL);
+  perror("run out_script");
+
+  return 1;
+}
+