initial pandora port, with hardware scaling and stuff
[gpsp.git] / pandora / pnd.c
diff --git a/pandora/pnd.c b/pandora/pnd.c
new file mode 100644 (file)
index 0000000..c845831
--- /dev/null
@@ -0,0 +1,315 @@
+/* gameplaySP - pandora backend
+ *
+ * Copyright (C) 2011 notaz <notasas@gmail.com>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "../common.h"
+#include <X11/keysym.h>
+#include "linux/omapfb.h" //
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include "linux/fbdev.h"
+#include "linux/xenv.h"
+
+enum gpsp_key {
+  GKEY_UP       = 1 << 0,
+  GKEY_LEFT     = 1 << 1,
+  GKEY_DOWN     = 1 << 2,
+  GKEY_RIGHT    = 1 << 3,
+  GKEY_START    = 1 << 4,
+  GKEY_SELECT   = 1 << 5,
+  GKEY_L        = 1 << 6,
+  GKEY_R        = 1 << 7,
+  GKEY_A        = 1 << 8,
+  GKEY_B        = 1 << 9,
+  GKEY_X        = 1 << 10,
+  GKEY_Y        = 1 << 11,
+  GKEY_1        = 1 << 12,
+  GKEY_2        = 1 << 13,
+  GKEY_3        = 1 << 14,
+  GKEY_4        = 1 << 15,
+  GKEY_MENU     = 1 << 16,
+};
+
+u32 button_plat_mask_to_config[PLAT_BUTTON_COUNT] =
+{
+  GKEY_UP,
+  GKEY_LEFT,
+  GKEY_DOWN,
+  GKEY_RIGHT,
+  GKEY_START,
+  GKEY_SELECT,
+  GKEY_L,
+  GKEY_R,
+  GKEY_A,
+  GKEY_B,
+  GKEY_X,
+  GKEY_Y,
+  GKEY_1,
+  GKEY_2,
+  GKEY_3,
+  GKEY_4,
+  GKEY_MENU,
+};
+
+u32 gamepad_config_map[PLAT_BUTTON_COUNT] =
+{
+  BUTTON_ID_UP,                 // Up
+  BUTTON_ID_LEFT,               // Left
+  BUTTON_ID_DOWN,               // Down
+  BUTTON_ID_RIGHT,              // Right
+  BUTTON_ID_START,              // Start
+  BUTTON_ID_SELECT,             // Select
+  BUTTON_ID_L,                  // Ltrigger
+  BUTTON_ID_R,                  // Rtrigger
+  BUTTON_ID_FPS,                // A
+  BUTTON_ID_A,                  // B
+  BUTTON_ID_B,                  // X
+  BUTTON_ID_MENU,               // Y
+  BUTTON_ID_SAVESTATE,          // 1
+  BUTTON_ID_LOADSTATE,          // 2
+  BUTTON_ID_FASTFORWARD,        // 3
+  BUTTON_ID_NONE,               // 4
+  BUTTON_ID_MENU                // Space
+};
+
+static const u32 xk_to_gkey[] = {
+  XK_Up, XK_Left, XK_Down, XK_Right, XK_Alt_L, XK_Control_L,
+  XK_Shift_L, XK_Control_R, XK_Home, XK_End, XK_Page_Down, XK_Page_Up,
+  XK_1, XK_2, XK_3, XK_4, XK_space,
+};
+
+static const u8 gkey_to_cursor[32] = {
+  [0 ... 31] = CURSOR_NONE,
+  [0] = CURSOR_UP, CURSOR_LEFT, CURSOR_DOWN, CURSOR_RIGHT, CURSOR_NONE, CURSOR_NONE,
+  CURSOR_L, CURSOR_R, CURSOR_SELECT, CURSOR_SELECT, CURSOR_EXIT, CURSOR_BACK,
+};
+
+struct vout_fbdev *fb;
+
+static int omap_setup_layer(int fd, int enabled, int x, int y, int w, int h, int first_call)
+{
+  struct omapfb_plane_info pi = { 0, };
+  struct omapfb_mem_info mi = { 0, };
+  int ret;
+
+  ret = ioctl(fd, OMAPFB_QUERY_PLANE, &pi);
+  if (ret != 0) {
+    perror("QUERY_PLANE");
+    return -1;
+  }
+
+  ret = ioctl(fd, OMAPFB_QUERY_MEM, &mi);
+  if (ret != 0) {
+    perror("QUERY_MEM");
+    return -1;
+  }
+
+  /* must disable when changing stuff */
+  if (pi.enabled) {
+    pi.enabled = 0;
+    ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
+    if (ret != 0)
+      perror("SETUP_PLANE");
+  }
+
+  if (first_call) {
+    mi.size = 640*512*3*3;
+    ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi);
+    if (ret != 0) {
+      perror("SETUP_MEM");
+      return -1;
+    }
+  }
+
+  pi.pos_x = x;
+  pi.pos_y = y;
+  pi.out_width = w;
+  pi.out_height = h;
+  pi.enabled = enabled;
+
+  ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
+  if (ret != 0) {
+    perror("SETUP_PLANE");
+    return -1;
+  }
+
+  return 0;
+}
+
+void gpsp_plat_init(void)
+{
+  int ret, w, h, fd;
+  const char *layer_fb_name;
+
+  ret = SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
+  if (ret != 0) {
+    fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
+    exit(1);
+  }
+
+  layer_fb_name = getenv("FBDEV_LAYER");
+  if (layer_fb_name == NULL)
+    layer_fb_name = "/dev/fb1";
+
+  ret = xenv_init();
+  if (ret != 0) {
+    fprintf(stderr, "xenv_init failed with %d\n", ret);
+    exit(1);
+  }
+
+  // must set the layer up first to be able to use it
+  fd = open(layer_fb_name, O_RDWR);
+  if (fd == -1) {
+    fprintf(stderr, "%s: ", layer_fb_name);
+    perror("open");
+    exit(1);
+  }
+
+  ret = omap_setup_layer(fd, 0, 0, 0, 400, 272, 1);
+  close(fd);
+  if (ret != 0) {
+    fprintf(stderr, "failed to set up layer, exiting.\n");
+    exit(1);
+  }
+
+  w = 240;
+  h = 160;
+  fb = vout_fbdev_init("/dev/fb1", &w, &h, 16, 4);
+  if (fb == NULL) {
+    fprintf(stderr, "vout_fbdev_init failed\n");
+    exit(1);
+  }
+
+  // default to 3x scale
+  screen_scale = 2;
+}
+
+void gpsp_plat_quit(void)
+{
+  xenv_finish();
+  omap_setup_layer(vout_fbdev_get_fd(fb), 0, 0, 0, 0, 0, 0);
+  vout_fbdev_finish(fb);
+  SDL_Quit();
+}
+
+u32 gpsp_plat_joystick_read(void)
+{
+  static int gkeystate;
+  int key, is_down, i;
+  int gkey = -1;
+  
+  key = xenv_update(&is_down);
+  for (i = 0; i < sizeof(xk_to_gkey) / sizeof(xk_to_gkey[0]); i++) {
+    if (key == xk_to_gkey[i]) {
+      gkey = i;
+      break;
+    }
+  }
+
+  if (gkey >= 0) {
+    if (is_down)
+      gkeystate |= 1 << gkey;
+    else
+      gkeystate &= ~(1 << gkey);
+  }
+  
+  return gkeystate;
+}
+
+u32 gpsp_plat_buttons_to_cursor(u32 buttons)
+{
+  int i;
+
+  if (buttons == 0)
+    return CURSOR_NONE;
+
+  for (i = 0; (buttons & 1) == 0; i++, buttons >>= 1)
+    ;
+
+  return gkey_to_cursor[i];
+}
+
+static void set_filter(int is_filtered)
+{
+  static int was_filtered = -1;
+  char buf[128];
+
+  if (is_filtered == was_filtered)
+    return;
+
+  snprintf(buf, sizeof(buf), "sudo -n /usr/pandora/scripts/op_videofir.sh %s",
+    is_filtered ? "default" : "none");
+  system(buf);
+  was_filtered = is_filtered;
+}
+
+void *fb_flip_screen(void)
+{
+  return vout_fbdev_flip(fb);
+}
+
+void fb_wait_vsync(void)
+{
+  vout_fbdev_wait_vsync(fb);
+}
+
+void fb_set_mode(int w, int h, int buffers, int scale, int filter)
+{
+  int lx, ly, lw = w, lh = h;
+  switch (scale) {
+    case 0:
+      lw = w;
+      lh = h;
+      break;
+    case 1:
+      lw = w * 2;
+      lh = h * 2;
+      break;
+    case 2:
+      lw = w * 3;
+      lh = h * 3;
+      break;
+    case 3:
+      lw = 800;
+      lh = 480;
+      break;
+    case 15:
+      lw = w * 2;
+      lh = h + h /2;
+      break;
+    default:
+      fprintf(stderr, "unknown scale: %d\n", scale);
+      break;
+  }
+  if (lw > 800)
+    lw = 800;
+  if (lh > 480)
+    lh = 480;
+  lx = 800 / 2 - lw / 2;
+  ly = 480 / 2 - lh / 2;
+
+  omap_setup_layer(vout_fbdev_get_fd(fb), 1, lx, ly, lw, lh, 0);
+  set_filter(filter);
+
+  vout_fbdev_resize(fb, w, h, 16, 0, 0, 0, 0, buffers);
+}
+
+// vim:shiftwidth=2:expandtab