From eb3668fc5dab138073cd4844208ac05b94086a4a Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 4 Sep 2011 20:02:19 +0300 Subject: [PATCH] initial pandora port, with hardware scaling and stuff --- .gitignore | 3 + common.h | 4 + gp2x/gp2x.c | 4 +- gp2x/gp2x.h | 3 +- gui.c | 77 +++++--- input.c | 2 +- main.c | 10 +- pandora/Makefile | 41 ++++ pandora/linux/fbdev.c | 255 ++++++++++++++++++++++++ pandora/linux/fbdev.h | 12 ++ pandora/linux/omapfb.h | 427 +++++++++++++++++++++++++++++++++++++++++ pandora/linux/xenv.c | 281 +++++++++++++++++++++++++++ pandora/linux/xenv.h | 5 + pandora/pnd.c | 315 ++++++++++++++++++++++++++++++ pandora/pnd.h | 12 ++ video.c | 55 +++++- 16 files changed, 1472 insertions(+), 34 deletions(-) create mode 100644 pandora/Makefile create mode 100644 pandora/linux/fbdev.c create mode 100644 pandora/linux/fbdev.h create mode 100644 pandora/linux/omapfb.h create mode 100644 pandora/linux/xenv.c create mode 100644 pandora/linux/xenv.h create mode 100644 pandora/pnd.c create mode 100644 pandora/pnd.h diff --git a/.gitignore b/.gitignore index 6298ed1..bf5c80b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ *.u *.z gpsp.gpe +tags +cscope.out +pandora/linux diff --git a/common.h b/common.h index f43d75c..7eea8b6 100644 --- a/common.h +++ b/common.h @@ -251,4 +251,8 @@ typedef u32 fixed16_16; // #define STDIO_DEBUG #endif +#ifdef PND_BUILD + #include "pandora/pnd.h" +#endif + #endif diff --git a/gp2x/gp2x.c b/gp2x/gp2x.c index 8bad610..ad3c215 100644 --- a/gp2x/gp2x.c +++ b/gp2x/gp2x.c @@ -39,7 +39,7 @@ static u32 gp2x_audio_volume = 74/2; static volatile u16 *gpsp_gp2x_memregs; static volatile u32 *gpsp_gp2x_memregl; -u32 button_plat_mask_to_config[] = +u32 button_plat_mask_to_config[PLAT_BUTTON_COUNT] = { GP2X_UP, GP2X_LEFT, @@ -59,7 +59,7 @@ u32 button_plat_mask_to_config[] = GP2X_VOL_MIDDLE }; -u32 gamepad_config_map[16] = +u32 gamepad_config_map[PLAT_BUTTON_COUNT] = { BUTTON_ID_UP, // Up BUTTON_ID_LEFT, // Left diff --git a/gp2x/gp2x.h b/gp2x/gp2x.h index 9218704..97b8d3c 100644 --- a/gp2x/gp2x.h +++ b/gp2x/gp2x.h @@ -33,7 +33,8 @@ void gpsp_plat_quit(void); u32 gpsp_plat_joystick_read(void); u32 gpsp_plat_buttons_to_cursor(u32 buttons); -extern u32 button_plat_mask_to_config[]; +#define PLAT_BUTTON_COUNT 16 +extern u32 button_plat_mask_to_config[PLAT_BUTTON_COUNT]; void gp2x_sound_volume(u32 volume_up); void gp2x_quit(); diff --git a/gui.c b/gui.c index 0184a18..22a39e0 100644 --- a/gui.c +++ b/gui.c @@ -569,11 +569,11 @@ struct _menu_option_type void (* action_function)(); void (* passive_function)(); struct _menu_type *sub_menu; - char *display_string; + const char *display_string; void *options; u32 *current_option; u32 num_options; - char *help_string; + const char *help_string; u32 line_number; menu_option_type_enum option_type; }; @@ -740,16 +740,26 @@ u32 gamepad_config_line_to_button[] = #endif +#ifdef PND_BUILD + +u32 gamepad_config_line_to_button[] = + { 0, 2, 1, 3, 8, 9, 10, 11, 6, 7, 4, 5, 12, 13, 14, 15 }; + +#endif + u8 *scale_options[] = { -#ifdef WIZ_BUILD +#ifdef PSP_BUILD + "unscaled 3:2", "scaled 3:2", "fullscreen 16:9" +#elif defined(WIZ_BUILD) "unscaled 3:2", "scaled 3:2 (slower)", "unscaled 3:2 (anti-tear)", "scaled 3:2 (anti-tear)" -#else +#elif defined(PND_BUILD) + "unscaled", "2x", "3x", "fullscreen" +#elif defined(GP2X_BUILD) "unscaled 3:2", "scaled 3:2", "fullscreen", "scaled 3:2 (software)" -#ifdef PSP_BUILD - " 16:9" -#endif +#else + "unscaled 3:2" #endif }; @@ -1024,7 +1034,7 @@ void get_savestate_snapshot(u8 *savestate_filename) else { memset(snapshot_buffer, 0, 240 * 160 * 2); - print_string_ext("No savestate exists for this slot.", + print_string_ext("No savestate in this slot.", 0xFFFF, 0x0000, 15, 75, snapshot_buffer, 240, 0, 0, FONT_HEIGHT); print_string("---------- --/--/---- --:--:-- ", COLOR_HELP_TEXT, COLOR_BG, 10, 40); @@ -1084,7 +1094,7 @@ u32 menu(u16 *original_screen) auto void choose_menu(); auto void clear_help(); - u8 *gamepad_help[] = + static const u8 * const gamepad_help[] = { "Up button on GBA d-pad.", "Down button on GBA d-pad.", @@ -1315,16 +1325,19 @@ u32 menu(u16 *original_screen) (u32 *)(&screen_scale), sizeof(scale_options) / sizeof(scale_options[0]), #ifndef GP2X_BUILD - "Determines how the GBA screen is resized in relation to the entire\n" - "screen. Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n" + "Determines how the GBA screen is resized in relation to the\n" + "entire screen." +#ifdef PSP_BUILD + " Select unscaled 3:2 for GBA resolution, scaled 3:2 for GBA\n" "aspect ratio scaled to fill the height of the PSP screen, and\n" "fullscreen to fill the entire PSP screen." +#endif #endif "", 2), #ifndef GP2X_BUILD string_selection_option(NULL, "Screen filtering", yes_no_options, (u32 *)(&screen_filter), 2, - "Determines whether or not bilinear filtering should be used when\n" + "Determines whether or not filtering should be used when\n" "scaling the screen. Selecting this will produce a more even and\n" "smooth image, at the cost of being blurry and having less vibrant\n" "colors.", 3), @@ -1352,8 +1365,8 @@ u32 menu(u16 *original_screen) #ifndef GP2X_BUILD "If objects in the game flicker at a regular rate certain manual\n" "frameskip values may cause them to normally disappear. Change this\n" - "value to 'random' to avoid this. Do not use otherwise, as it tends to\n" - "make the image quality worse, especially in high motion games." + "value to 'random' to avoid this. Do not use otherwise, as it tends\n" + "to make the image quality worse, especially in high motion games." #endif "", 7), string_selection_option(NULL, "Audio output", yes_no_options, @@ -1395,25 +1408,29 @@ u32 menu(u16 *original_screen) cheat_option(7), cheat_option(8), cheat_option(9), +#if defined(PSP_BUILD) || defined(GP2X_BUILD) string_selection_option(NULL, "Clock speed", clock_speed_options, &clock_speed_number, sizeof(clock_speed_options) / sizeof(clock_speed_options[0]), "Change the clock speed of the device. Higher clock\n" "speed will yield better performance, but will drain\n" "battery life further.", 11), +#endif string_selection_option(NULL, "Update backup", update_backup_options, &update_backup_flag, 2, #ifdef GP2X_BUILD "Determines when in-game save files should be\n" - "written back to SD card.", + "written back to SD card." #else "Determines when in-game save files should be written back to\n" - "memstick. If set to 'automatic' writebacks will occur shortly after\n" - "the game's backup is altered. On 'exit only' it will only be written\n" - "back when you exit from this menu (NOT from using the home button).\n" - "Use the latter with extreme care.", + "card. If set to 'automatic' writebacks will occur shortly after\n" + "the game's backup is altered. On 'exit only' it will only be\n" + "written back when you exit from this menu.\n" +#ifdef PSP + "(NOT from using the home button), use the latter with extreme care." +#endif #endif - 12), + "", 12), submenu_option(NULL, "Back", "Return to the main menu.", 14) }; @@ -1483,7 +1500,7 @@ u32 menu(u16 *original_screen) #endif -#ifdef GP2X_BUILD +#if defined(GP2X_BUILD) || defined(PND_BUILD) menu_option_type gamepad_config_options[] = { @@ -1503,10 +1520,18 @@ u32 menu(u16 *original_screen) gamepad_config_option("Start ", 10), #endif gamepad_config_option("Select ", 11), -#ifndef WIZ_BUILD +#if !defined(WIZ_BUILD) && !defined(PND_BUILD) gamepad_config_option("Stick Push ", 12), #endif +#ifdef PND_BUILD + gamepad_config_option("1 ", 12), + gamepad_config_option("2 ", 13), + gamepad_config_option("3 ", 14), + gamepad_config_option("4 ", 15), + submenu_option(NULL, "Back", "Return to the main menu.", 16) +#else submenu_option(NULL, "Back", "Return to the main menu.", 14) +#endif }; @@ -1665,13 +1690,13 @@ u32 menu(u16 *original_screen) if(display_option == current_option) { - print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 10, - (display_option->line_number * 10) + 40, 41); + print_string_pad(line_buffer, COLOR_ACTIVE_ITEM, COLOR_BG, 6, + (display_option->line_number * 10) + 40, 36); } else { - print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 10, - (display_option->line_number * 10) + 40, 41); + print_string_pad(line_buffer, COLOR_INACTIVE_ITEM, COLOR_BG, 6, + (display_option->line_number * 10) + 40, 36); } } diff --git a/input.c b/input.c index 4b908bb..acd01f5 100644 --- a/input.c +++ b/input.c @@ -454,7 +454,7 @@ u32 update_input() handled_buttons = (last_buttons ^ buttons) & buttons; last_buttons = buttons; - for(i = 0; i < 16; i++) + for(i = 0; i < PLAT_BUTTON_COUNT; i++) { if(handled_buttons & button_plat_mask_to_config[i]) button_id = gamepad_config_map[i]; diff --git a/main.c b/main.c index 0d88b37..ad79024 100644 --- a/main.c +++ b/main.c @@ -203,9 +203,6 @@ int main(int argc, char *argv[]) #endif getcwd(main_path, 512); - load_config_file(); - - gamepak_filename[0] = 0; #ifdef PSP_BUILD delay_us(2500000); @@ -214,6 +211,9 @@ int main(int argc, char *argv[]) #ifndef PC_BUILD gpsp_plat_init(); #endif + load_config_file(); + + gamepak_filename[0] = 0; init_video(); @@ -235,7 +235,11 @@ int main(int argc, char *argv[]) debug_screen_printl("a860e8c0b6d573d191e4ec7db1b1e4f6 "); debug_screen_printl(" "); debug_screen_printl("When you do get it name it gba_bios.bin and put it"); +#ifdef PND_BUILD + debug_screen_printl("in /pandora/appdata/gpsp/ . "); +#else debug_screen_printl("in the same directory as gpSP. "); +#endif debug_screen_printl(" "); debug_screen_printl("Press any button to exit. "); diff --git a/pandora/Makefile b/pandora/Makefile new file mode 100644 index 0000000..090cccb --- /dev/null +++ b/pandora/Makefile @@ -0,0 +1,41 @@ +# gpSP makefile +# Gilead Kutnick - Exophase +# pandora port - notaz + +# Global definitions + +CC = $(CROSS_COMPILE)gcc + +OBJS = pnd.o main.o cpu.o memory.o video.o input.o sound.o gui.o \ + cheats.o zip.o cpu_threaded.o arm_stub.o video_blend.o warm.o \ + linux/fbdev.o linux/xenv.o +BIN = gpsp + +# Platform specific definitions + +VPATH += .. ../arm +CFLAGS += -DARM_ARCH -DPND_BUILD +CFLAGS += -funsigned-char +CFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfloat-abi=softfp -ffast-math +CFLAGS += -fno-common -fno-builtin +CFLAGS += -ggdb +CFLAGS += -O2 + +# expecting to have PATH set up to get correct sdl-config first +CFLAGS += `sdl-config --cflags` +LIBS += `sdl-config --libs` +LIBS += -ldl -lpthread -lz + +# Compilation: + +%.o: %.S + $(CC) $(CFLAGS) -c -o $@ $< + +all: $(BIN) + +$(BIN): $(OBJS) + $(CC) $(OBJS) $(LIBS) -o $(BIN) + +clean: + rm -f *.o $(BIN) + diff --git a/pandora/linux/fbdev.c b/pandora/linux/fbdev.c new file mode 100644 index 0000000..9d532a5 --- /dev/null +++ b/pandora/linux/fbdev.c @@ -0,0 +1,255 @@ +/* + * (C) Gražvydas "notaz" Ignotas, 2009-2010 + * + * This work is licensed under the terms of any of these licenses + * (at your option): + * - GNU GPL, version 2 or later. + * - GNU LGPL, version 2.1 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fbdev.h" + +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; + int fb_size; + int buffer_count; + int top_border, bottom_border; +}; + +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->top_border + fbdev->fbvar_new.yres + fbdev->bottom_border) * draw_buf + + fbdev->top_border; + + ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new); + + return (char *)fbdev->mem + fbdev->fb_size * fbdev->buffer_write; +} + +void vout_fbdev_wait_vsync(struct vout_fbdev *fbdev) +{ + int arg = 0; + ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &arg); +} + +/* it is recommended to call vout_fbdev_clear() before this */ +void *vout_fbdev_resize(struct vout_fbdev *fbdev, int w, int h, int bpp, + int left_border, int right_border, int top_border, int bottom_border, int buffer_cnt) +{ + int w_total = left_border + w + right_border; + int h_total = top_border + h + bottom_border; + size_t mem_size; + int ret; + + // unblank to be sure the mode is really accepted + ioctl(fbdev->fd, FBIOBLANK, FB_BLANK_UNBLANK); + + if (fbdev->fbvar_new.bits_per_pixel != bpp || + fbdev->fbvar_new.xres != w || + fbdev->fbvar_new.yres != h || + fbdev->fbvar_new.xres_virtual != w_total|| + fbdev->fbvar_new.yres_virtual < h_total || + fbdev->fbvar_new.xoffset != left_border || + fbdev->buffer_count != buffer_cnt) + { + if (fbdev->fbvar_new.bits_per_pixel != bpp || + w != fbdev->fbvar_new.xres || h != fbdev->fbvar_new.yres) + printf(" switching to %dx%d@%d\n", w, h, bpp); + + fbdev->fbvar_new.xres = w; + fbdev->fbvar_new.yres = h; + fbdev->fbvar_new.xres_virtual = w_total; + fbdev->fbvar_new.yres_virtual = h_total * buffer_cnt; + fbdev->fbvar_new.xoffset = left_border; + fbdev->fbvar_new.yoffset = top_border; + fbdev->fbvar_new.bits_per_pixel = bpp; + fbdev->fbvar_new.nonstd = 0; // can set YUV here on omapfb + fbdev->buffer_count = buffer_cnt; + fbdev->buffer_write = 1; + + // seems to help a bit to avoid glitches + vout_fbdev_wait_vsync(fbdev); + + ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new); + if (ret == -1) { + // retry with no multibuffering + fbdev->fbvar_new.yres_virtual = h_total; + ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new); + if (ret == -1) { + perror("FBIOPUT_VSCREENINFO ioctl"); + return NULL; + } + fbdev->buffer_count = 1; + fbdev->buffer_write = 0; + fprintf(stderr, "Warning: failed to increase virtual resolution, " + "multibuffering disabled\n"); + } + + } + + fbdev->fb_size = w_total * h_total * bpp / 8; + fbdev->top_border = top_border; + fbdev->bottom_border = bottom_border; + + mem_size = fbdev->fb_size * fbdev->buffer_count; + if (fbdev->mem_size >= mem_size) + goto out; + + if (fbdev->mem != NULL) + munmap(fbdev->mem, fbdev->mem_size); + + fbdev->mem = mmap(0, 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", mem_size); + fbdev->buffer_count = 1; + fbdev->buffer_write = 0; + mem_size = fbdev->fb_size; + fbdev->mem = mmap(0, mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0); + } + if (fbdev->mem == MAP_FAILED) { + fbdev->mem = NULL; + fbdev->mem_size = 0; + perror("mmap framebuffer"); + return NULL; + } + + fbdev->mem_size = mem_size; + +out: + return (char *)fbdev->mem + fbdev->fb_size * fbdev->buffer_write; +} + +void vout_fbdev_clear(struct vout_fbdev *fbdev) +{ + memset(fbdev->mem, 0, fbdev->mem_size); +} + +void vout_fbdev_clear_lines(struct vout_fbdev *fbdev, int y, int count) +{ + int stride = fbdev->fbvar_new.xres_virtual * fbdev->fbvar_new.bits_per_pixel / 8; + int i; + + if (y + count > fbdev->top_border + fbdev->fbvar_new.yres) + count = fbdev->top_border + fbdev->fbvar_new.yres - y; + + if (y >= 0 && count > 0) + for (i = 0; i < fbdev->buffer_count; i++) + memset((char *)fbdev->mem + fbdev->fb_size * i + y * stride, 0, stride * count); +} + +int vout_fbdev_get_fd(struct vout_fbdev *fbdev) +{ + return fbdev->fd; +} + +struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int bpp, int buffer_cnt) +{ + struct vout_fbdev *fbdev; + int req_w, req_h; + void *pret; + int ret; + + fbdev = calloc(1, sizeof(*fbdev)); + if (fbdev == NULL) + return NULL; + + fbdev->fd = open(fbdev_name, O_RDWR); + 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; + + req_w = fbdev->fbvar_new.xres; + if (*w != 0) + req_w = *w; + req_h = fbdev->fbvar_new.yres; + if (*h != 0) + req_h = *h; + + pret = vout_fbdev_resize(fbdev, req_w, req_h, bpp, 0, 0, 0, 0, buffer_cnt); + if (pret == NULL) + goto fail; + + printf("%s: %ix%i@%d\n", fbdev_name, fbdev->fbvar_new.xres, fbdev->fbvar_new.yres, + fbdev->fbvar_new.bits_per_pixel); + *w = fbdev->fbvar_new.xres; + *h = fbdev->fbvar_new.yres; + + memset(fbdev->mem, 0, fbdev->mem_size); + + // 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_new.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); +} + diff --git a/pandora/linux/fbdev.h b/pandora/linux/fbdev.h new file mode 100644 index 0000000..2db9163 --- /dev/null +++ b/pandora/linux/fbdev.h @@ -0,0 +1,12 @@ +struct vout_fbdev; + +struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int bpp, int buffer_count); +void *vout_fbdev_flip(struct vout_fbdev *fbdev); +void vout_fbdev_wait_vsync(struct vout_fbdev *fbdev); +void *vout_fbdev_resize(struct vout_fbdev *fbdev, int w, int h, int bpp, + int left_border, int right_border, int top_border, int bottom_border, + int buffer_count); +void vout_fbdev_clear(struct vout_fbdev *fbdev); +void vout_fbdev_clear_lines(struct vout_fbdev *fbdev, int y, int count); +int vout_fbdev_get_fd(struct vout_fbdev *fbdev); +void vout_fbdev_finish(struct vout_fbdev *fbdev); diff --git a/pandora/linux/omapfb.h b/pandora/linux/omapfb.h new file mode 100644 index 0000000..f156e3a --- /dev/null +++ b/pandora/linux/omapfb.h @@ -0,0 +1,427 @@ +/* + * File: arch/arm/plat-omap/include/mach/omapfb.h + * + * Framebuffer driver for TI OMAP boards + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __OMAPFB_H +#define __OMAPFB_H + +#include +#include + +/* IOCTL commands. */ + +#define OMAP_IOW(num, dtype) _IOW('O', num, dtype) +#define OMAP_IOR(num, dtype) _IOR('O', num, dtype) +#define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype) +#define OMAP_IO(num) _IO('O', num) + +#define OMAPFB_MIRROR OMAP_IOW(31, int) +#define OMAPFB_SYNC_GFX OMAP_IO(37) +#define OMAPFB_VSYNC OMAP_IO(38) +#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int) +#define OMAPFB_GET_CAPS OMAP_IOR(42, struct omapfb_caps) +#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int) +#define OMAPFB_LCD_TEST OMAP_IOW(45, int) +#define OMAPFB_CTRL_TEST OMAP_IOW(46, int) +#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old) +#define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key) +#define OMAPFB_GET_COLOR_KEY OMAP_IOW(51, struct omapfb_color_key) +#define OMAPFB_SETUP_PLANE OMAP_IOW(52, struct omapfb_plane_info) +#define OMAPFB_QUERY_PLANE OMAP_IOW(53, struct omapfb_plane_info) +#define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window) +#define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info) +#define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info) +#define OMAPFB_WAITFORVSYNC OMAP_IO(57) +#define OMAPFB_MEMORY_READ OMAP_IOR(58, struct omapfb_memory_read) + +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) +#endif + +#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff +#define OMAPFB_CAPS_LCDC_MASK 0x00fff000 +#define OMAPFB_CAPS_PANEL_MASK 0xff000000 + +#define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000 +#define OMAPFB_CAPS_TEARSYNC 0x00002000 +#define OMAPFB_CAPS_PLANE_RELOCATE_MEM 0x00004000 +#define OMAPFB_CAPS_PLANE_SCALE 0x00008000 +#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE 0x00010000 +#define OMAPFB_CAPS_WINDOW_SCALE 0x00020000 +#define OMAPFB_CAPS_WINDOW_OVERLAY 0x00040000 +#define OMAPFB_CAPS_WINDOW_ROTATE 0x00080000 +#define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000 + +/* Values from DSP must map to lower 16-bits */ +#define OMAPFB_FORMAT_MASK 0x00ff +#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100 +#define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200 +#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400 +#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY 0x0800 +#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY 0x1000 + +#define OMAPFB_EVENT_READY 1 +#define OMAPFB_EVENT_DISABLED 2 + +#define OMAPFB_MEMTYPE_SDRAM 0 +#define OMAPFB_MEMTYPE_SRAM 1 +#define OMAPFB_MEMTYPE_MAX 1 + +enum omapfb_color_format { + OMAPFB_COLOR_RGB565 = 0, + OMAPFB_COLOR_YUV422, + OMAPFB_COLOR_YUV420, + OMAPFB_COLOR_CLUT_8BPP, + OMAPFB_COLOR_CLUT_4BPP, + OMAPFB_COLOR_CLUT_2BPP, + OMAPFB_COLOR_CLUT_1BPP, + OMAPFB_COLOR_RGB444, + OMAPFB_COLOR_YUY422, + + OMAPFB_COLOR_ARGB16, + OMAPFB_COLOR_RGB24U, /* RGB24, 32-bit container */ + OMAPFB_COLOR_RGB24P, /* RGB24, 24-bit container */ + OMAPFB_COLOR_ARGB32, + OMAPFB_COLOR_RGBA32, + OMAPFB_COLOR_RGBX32, +}; + +struct omapfb_update_window { + __u32 x, y; + __u32 width, height; + __u32 format; + __u32 out_x, out_y; + __u32 out_width, out_height; + __u32 reserved[8]; +}; + +struct omapfb_update_window_old { + __u32 x, y; + __u32 width, height; + __u32 format; +}; + +enum omapfb_plane { + OMAPFB_PLANE_GFX = 0, + OMAPFB_PLANE_VID1, + OMAPFB_PLANE_VID2, +}; + +enum omapfb_channel_out { + OMAPFB_CHANNEL_OUT_LCD = 0, + OMAPFB_CHANNEL_OUT_DIGIT, +}; + +struct omapfb_plane_info { + __u32 pos_x; + __u32 pos_y; + __u8 enabled; + __u8 channel_out; + __u8 mirror; + __u8 reserved1; + __u32 out_width; + __u32 out_height; + __u32 reserved2[12]; +}; + +struct omapfb_mem_info { + __u32 size; + __u8 type; + __u8 reserved[3]; +}; + +struct omapfb_caps { + __u32 ctrl; + __u32 plane_color; + __u32 wnd_color; +}; + +enum omapfb_color_key_type { + OMAPFB_COLOR_KEY_DISABLED = 0, + OMAPFB_COLOR_KEY_GFX_DST, + OMAPFB_COLOR_KEY_VID_SRC, +}; + +struct omapfb_color_key { + __u8 channel_out; + __u32 background; + __u32 trans_key; + __u8 key_type; +}; + +enum omapfb_update_mode { + OMAPFB_UPDATE_DISABLED = 0, + OMAPFB_AUTO_UPDATE, + OMAPFB_MANUAL_UPDATE +}; + +struct omapfb_memory_read { + __u16 x; + __u16 y; + __u16 w; + __u16 h; + size_t buffer_size; + void *buffer; +}; + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +#include + +#define OMAP_LCDC_INV_VSYNC 0x0001 +#define OMAP_LCDC_INV_HSYNC 0x0002 +#define OMAP_LCDC_INV_PIX_CLOCK 0x0004 +#define OMAP_LCDC_INV_OUTPUT_EN 0x0008 +#define OMAP_LCDC_HSVS_RISING_EDGE 0x0010 +#define OMAP_LCDC_HSVS_OPPOSITE 0x0020 + +#define OMAP_LCDC_SIGNAL_MASK 0x003f + +#define OMAP_LCDC_PANEL_TFT 0x0100 + +#define OMAPFB_PLANE_XRES_MIN 8 +#define OMAPFB_PLANE_YRES_MIN 8 + +#ifdef CONFIG_ARCH_OMAP1 +#define OMAPFB_PLANE_NUM 1 +#else +#define OMAPFB_PLANE_NUM 3 +#endif + +struct omapfb_device; + +struct lcd_panel { + const char *name; + int config; /* TFT/STN, signal inversion */ + int bpp; /* Pixel format in fb mem */ + int data_lines; /* Lines on LCD HW interface */ + + int x_res, y_res; + int pixel_clock; /* In kHz */ + int hsw; /* Horizontal synchronization + pulse width */ + int hfp; /* Horizontal front porch */ + int hbp; /* Horizontal back porch */ + int vsw; /* Vertical synchronization + pulse width */ + int vfp; /* Vertical front porch */ + int vbp; /* Vertical back porch */ + int acb; /* ac-bias pin frequency */ + int pcd; /* pixel clock divider. + Obsolete use pixel_clock instead */ + + int (*init) (struct lcd_panel *panel, + struct omapfb_device *fbdev); + void (*cleanup) (struct lcd_panel *panel); + int (*enable) (struct lcd_panel *panel); + void (*disable) (struct lcd_panel *panel); + unsigned long (*get_caps) (struct lcd_panel *panel); + int (*set_bklight_level)(struct lcd_panel *panel, + unsigned int level); + unsigned int (*get_bklight_level)(struct lcd_panel *panel); + unsigned int (*get_bklight_max) (struct lcd_panel *panel); + int (*run_test) (struct lcd_panel *panel, int test_num); +}; + +struct extif_timings { + int cs_on_time; + int cs_off_time; + int we_on_time; + int we_off_time; + int re_on_time; + int re_off_time; + int we_cycle_time; + int re_cycle_time; + int cs_pulse_width; + int access_time; + + int clk_div; + + u32 tim[5]; /* set by extif->convert_timings */ + + int converted; +}; + +struct lcd_ctrl_extif { + int (*init) (struct omapfb_device *fbdev); + void (*cleanup) (void); + void (*get_clk_info) (u32 *clk_period, u32 *max_clk_div); + unsigned long (*get_max_tx_rate)(void); + int (*convert_timings) (struct extif_timings *timings); + void (*set_timings) (const struct extif_timings *timings); + void (*set_bits_per_cycle)(int bpc); + void (*write_command) (const void *buf, unsigned int len); + void (*read_data) (void *buf, unsigned int len); + void (*write_data) (const void *buf, unsigned int len); + void (*transfer_area) (int width, int height, + void (callback)(void * data), void *data); + int (*setup_tearsync) (unsigned pin_cnt, + unsigned hs_pulse_time, unsigned vs_pulse_time, + int hs_pol_inv, int vs_pol_inv, int div); + int (*enable_tearsync) (int enable, unsigned line); + + unsigned long max_transmit_size; +}; + +struct omapfb_notifier_block { + struct notifier_block nb; + void *data; + int plane_idx; +}; + +typedef int (*omapfb_notifier_callback_t)(struct notifier_block *, + unsigned long event, + void *fbi); + +struct omapfb_mem_region { + u32 paddr; + void __iomem *vaddr; + unsigned long size; + u8 type; /* OMAPFB_PLANE_MEM_* */ + enum omapfb_color_format format;/* OMAPFB_COLOR_* */ + unsigned format_used:1; /* Must be set when format is set. + * Needed b/c of the badly chosen 0 + * base for OMAPFB_COLOR_* values + */ + unsigned alloc:1; /* allocated by the driver */ + unsigned map:1; /* kernel mapped by the driver */ +}; + +struct omapfb_mem_desc { + int region_cnt; + struct omapfb_mem_region region[OMAPFB_PLANE_NUM]; +}; + +struct lcd_ctrl { + const char *name; + void *data; + + int (*init) (struct omapfb_device *fbdev, + int ext_mode, + struct omapfb_mem_desc *req_md); + void (*cleanup) (void); + void (*bind_client) (struct omapfb_notifier_block *nb); + void (*get_caps) (int plane, struct omapfb_caps *caps); + int (*set_update_mode)(enum omapfb_update_mode mode); + enum omapfb_update_mode (*get_update_mode)(void); + int (*setup_plane) (int plane, int channel_out, + unsigned long offset, + int screen_width, + int pos_x, int pos_y, int width, + int height, int color_mode); + int (*set_rotate) (int angle); + int (*setup_mem) (int plane, size_t size, + int mem_type, unsigned long *paddr); + int (*mmap) (struct fb_info *info, + struct vm_area_struct *vma); + int (*set_scale) (int plane, + int orig_width, int orig_height, + int out_width, int out_height); + int (*enable_plane) (int plane, int enable); + int (*update_window) (struct fb_info *fbi, + struct omapfb_update_window *win, + void (*callback)(void *), + void *callback_data); + void (*sync) (void); + void (*suspend) (void); + void (*resume) (void); + int (*run_test) (int test_num); + int (*setcolreg) (u_int regno, u16 red, u16 green, + u16 blue, u16 transp, + int update_hw_mem); + int (*set_color_key) (struct omapfb_color_key *ck); + int (*get_color_key) (struct omapfb_color_key *ck); +}; + +enum omapfb_state { + OMAPFB_DISABLED = 0, + OMAPFB_SUSPENDED= 99, + OMAPFB_ACTIVE = 100 +}; + +struct omapfb_plane_struct { + int idx; + struct omapfb_plane_info info; + enum omapfb_color_format color_mode; + struct omapfb_device *fbdev; +}; + +struct omapfb_device { + int state; + int ext_lcdc; /* Using external + LCD controller */ + struct mutex rqueue_mutex; + + int palette_size; + u32 pseudo_palette[17]; + + struct lcd_panel *panel; /* LCD panel */ + const struct lcd_ctrl *ctrl; /* LCD controller */ + const struct lcd_ctrl *int_ctrl; /* internal LCD ctrl */ + struct lcd_ctrl_extif *ext_if; /* LCD ctrl external + interface */ + struct device *dev; + struct fb_var_screeninfo new_var; /* for mode changes */ + + struct omapfb_mem_desc mem_desc; + struct fb_info *fb_info[OMAPFB_PLANE_NUM]; +}; + +struct omapfb_platform_data { + struct omap_lcd_config lcd; + struct omapfb_mem_desc mem_desc; + void *ctrl_platform_data; +}; + +#ifdef CONFIG_ARCH_OMAP1 +extern struct lcd_ctrl omap1_lcd_ctrl; +#else +extern struct lcd_ctrl omap2_disp_ctrl; +#endif + +extern void omapfb_set_platform_data(struct omapfb_platform_data *data); + +extern void omapfb_reserve_sdram(void); +extern void omapfb_register_panel(struct lcd_panel *panel); +extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval); +extern void omapfb_notify_clients(struct omapfb_device *fbdev, + unsigned long event); +extern int omapfb_register_client(struct omapfb_notifier_block *nb, + omapfb_notifier_callback_t callback, + void *callback_data); +extern int omapfb_unregister_client(struct omapfb_notifier_block *nb); +extern int omapfb_update_window_async(struct fb_info *fbi, + struct omapfb_update_window *win, + void (*callback)(void *), + void *callback_data); + +/* in arch/arm/plat-omap/fb.c */ +extern void omapfb_set_ctrl_platform_data(void *pdata); + +#endif /* __KERNEL__ */ + +#endif /* __OMAPFB_H */ diff --git a/pandora/linux/xenv.c b/pandora/linux/xenv.c new file mode 100644 index 0000000..8295b2c --- /dev/null +++ b/pandora/linux/xenv.c @@ -0,0 +1,281 @@ +/* + * (C) Gražvydas "notaz" Ignotas, 2009-2011 + * + * This work is licensed under the terms of any of these licenses + * (at your option): + * - GNU GPL, version 2 or later. + * - GNU LGPL, version 2.1 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define PFX "xenv: " + +#define FPTR(f) typeof(f) * p##f +#define FPTR_LINK(xf, dl, f) { \ + xf.p##f = dlsym(dl, #f); \ + if (xf.p##f == NULL) { \ + fprintf(stderr, "missing symbol: %s\n", #f); \ + goto fail; \ + } \ +} + +struct xstuff { + Display *display; + FPTR(XCreateBitmapFromData); + FPTR(XCreatePixmapCursor); + FPTR(XFreePixmap); + FPTR(XOpenDisplay); + FPTR(XDisplayName); + FPTR(XCloseDisplay); + FPTR(XCreateSimpleWindow); + FPTR(XChangeWindowAttributes); + FPTR(XSelectInput); + FPTR(XMapWindow); + FPTR(XNextEvent); + FPTR(XCheckTypedEvent); + FPTR(XUnmapWindow); + FPTR(XGrabKeyboard); + FPTR(XPending); + FPTR(XLookupKeysym); + FPTR(XkbSetDetectableAutoRepeat); +}; + +static struct xstuff g_xstuff; + +static Cursor transparent_cursor(struct xstuff *xf, Display *display, Window win) +{ + Cursor cursor; + Pixmap pix; + XColor dummy; + char d = 0; + + memset(&dummy, 0, sizeof(dummy)); + pix = xf->pXCreateBitmapFromData(display, win, &d, 1, 1); + cursor = xf->pXCreatePixmapCursor(display, pix, pix, + &dummy, &dummy, 0, 0); + xf->pXFreePixmap(display, pix); + return cursor; +} + +static int x11h_init(void) +{ + unsigned int display_width, display_height; + Display *display; + XSetWindowAttributes attributes; + Window win; + Visual *visual; + void *x11lib; + int screen; + + memset(&g_xstuff, 0, sizeof(g_xstuff)); + x11lib = dlopen("libX11.so.6", RTLD_LAZY); + if (x11lib == NULL) { + fprintf(stderr, "libX11.so load failed:\n%s\n", dlerror()); + goto fail; + } + FPTR_LINK(g_xstuff, x11lib, XCreateBitmapFromData); + FPTR_LINK(g_xstuff, x11lib, XCreatePixmapCursor); + FPTR_LINK(g_xstuff, x11lib, XFreePixmap); + FPTR_LINK(g_xstuff, x11lib, XOpenDisplay); + FPTR_LINK(g_xstuff, x11lib, XDisplayName); + FPTR_LINK(g_xstuff, x11lib, XCloseDisplay); + FPTR_LINK(g_xstuff, x11lib, XCreateSimpleWindow); + FPTR_LINK(g_xstuff, x11lib, XChangeWindowAttributes); + FPTR_LINK(g_xstuff, x11lib, XSelectInput); + FPTR_LINK(g_xstuff, x11lib, XMapWindow); + FPTR_LINK(g_xstuff, x11lib, XNextEvent); + FPTR_LINK(g_xstuff, x11lib, XCheckTypedEvent); + FPTR_LINK(g_xstuff, x11lib, XUnmapWindow); + FPTR_LINK(g_xstuff, x11lib, XGrabKeyboard); + FPTR_LINK(g_xstuff, x11lib, XPending); + FPTR_LINK(g_xstuff, x11lib, XLookupKeysym); + FPTR_LINK(g_xstuff, x11lib, XkbSetDetectableAutoRepeat); + + //XInitThreads(); + + g_xstuff.display = display = g_xstuff.pXOpenDisplay(NULL); + if (display == NULL) + { + fprintf(stderr, "cannot connect to X server %s, X handling disabled.\n", + g_xstuff.pXDisplayName(NULL)); + goto fail2; + } + + visual = DefaultVisual(display, 0); + if (visual->class != TrueColor) + fprintf(stderr, PFX "warning: non true color visual\n"); + + printf(PFX "X vendor: %s, rel: %d, display: %s, protocol ver: %d.%d\n", ServerVendor(display), + VendorRelease(display), DisplayString(display), ProtocolVersion(display), + ProtocolRevision(display)); + + screen = DefaultScreen(display); + + display_width = DisplayWidth(display, screen); + display_height = DisplayHeight(display, screen); + printf(PFX "display is %dx%d\n", display_width, display_height); + + win = g_xstuff.pXCreateSimpleWindow(display, + RootWindow(display, screen), + 0, 0, display_width, display_height, 0, + BlackPixel(display, screen), + BlackPixel(display, screen)); + + attributes.override_redirect = True; + attributes.cursor = transparent_cursor(&g_xstuff, display, win); + g_xstuff.pXChangeWindowAttributes(display, win, CWOverrideRedirect | CWCursor, &attributes); + + g_xstuff.pXSelectInput(display, win, ExposureMask | FocusChangeMask | KeyPressMask | KeyReleaseMask); + g_xstuff.pXMapWindow(display, win); + g_xstuff.pXGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime); + g_xstuff.pXkbSetDetectableAutoRepeat(display, 1, NULL); + // XSetIOErrorHandler + + return 0; +fail2: + dlclose(x11lib); +fail: + g_xstuff.display = NULL; + fprintf(stderr, "x11 handling disabled.\n"); + return -1; +} + +static int x11h_update(int *is_down) +{ + XEvent evt; + + while (g_xstuff.pXPending(g_xstuff.display)) + { + g_xstuff.pXNextEvent(g_xstuff.display, &evt); + switch (evt.type) + { + case Expose: + while (g_xstuff.pXCheckTypedEvent(g_xstuff.display, Expose, &evt)) + ; + break; + + case KeyPress: + *is_down = 1; + return g_xstuff.pXLookupKeysym(&evt.xkey, 0); + + case KeyRelease: + *is_down = 0; + return g_xstuff.pXLookupKeysym(&evt.xkey, 0); + // printf("press %d\n", evt.xkey.keycode); + } + } + + return NoSymbol; +} + +static struct termios g_kbd_termios_saved; +static int g_kbdfd; + +static int tty_init(void) +{ + struct termios kbd_termios; + int mode; + + g_kbdfd = open("/dev/tty", O_RDWR); + if (g_kbdfd == -1) { + perror(PFX "open /dev/tty"); + return -1; + } + + if (ioctl(g_kbdfd, KDGETMODE, &mode) == -1) { + perror(PFX "(not hiding FB): KDGETMODE"); + goto fail; + } + + if (tcgetattr(g_kbdfd, &kbd_termios) == -1) { + perror(PFX "tcgetattr"); + goto fail; + } + + g_kbd_termios_saved = kbd_termios; + kbd_termios.c_lflag &= ~(ICANON | ECHO); // | ISIG); + kbd_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); + kbd_termios.c_cc[VMIN] = 0; + kbd_termios.c_cc[VTIME] = 0; + + if (tcsetattr(g_kbdfd, TCSAFLUSH, &kbd_termios) == -1) { + perror(PFX "tcsetattr"); + goto fail; + } + + if (ioctl(g_kbdfd, KDSETMODE, KD_GRAPHICS) == -1) { + perror(PFX "KDSETMODE KD_GRAPHICS"); + tcsetattr(g_kbdfd, TCSAFLUSH, &g_kbd_termios_saved); + goto fail; + } + + return 0; + +fail: + close(g_kbdfd); + g_kbdfd = -1; + return -1; +} + +static void tty_end(void) +{ + if (g_kbdfd <= 0) + return; + + if (ioctl(g_kbdfd, KDSETMODE, KD_TEXT) == -1) + perror(PFX "KDSETMODE KD_TEXT"); + + if (tcsetattr(g_kbdfd, TCSAFLUSH, &g_kbd_termios_saved) == -1) + perror(PFX "tcsetattr"); + + close(g_kbdfd); + g_kbdfd = -1; +} + +int xenv_init(void) +{ + int ret; + + ret = x11h_init(); + if (ret == 0) + return 0; + + ret = tty_init(); + if (ret == 0) + return 0; + + fprintf(stderr, PFX "error: both x11h_init and tty_init failed\n"); + return -1; +} + +int xenv_update(int *is_down) +{ + if (g_xstuff.display) + return x11h_update(is_down); + + // TODO: read tty? + return -1; +} + +void xenv_finish(void) +{ + // TODO: cleanup X? + tty_end(); +} diff --git a/pandora/linux/xenv.h b/pandora/linux/xenv.h new file mode 100644 index 0000000..948381e --- /dev/null +++ b/pandora/linux/xenv.h @@ -0,0 +1,5 @@ + +int xenv_init(void); +int xenv_update(int *is_down); +void xenv_finish(void); + diff --git a/pandora/pnd.c b/pandora/pnd.c new file mode 100644 index 0000000..c845831 --- /dev/null +++ b/pandora/pnd.c @@ -0,0 +1,315 @@ +/* gameplaySP - pandora backend + * + * Copyright (C) 2011 notaz + * + * 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 +#include "linux/omapfb.h" // +#include +#include +#include +#include + +#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 diff --git a/pandora/pnd.h b/pandora/pnd.h new file mode 100644 index 0000000..2161756 --- /dev/null +++ b/pandora/pnd.h @@ -0,0 +1,12 @@ +void gpsp_plat_init(void); +void gpsp_plat_quit(void); + +u32 gpsp_plat_joystick_read(void); +u32 gpsp_plat_buttons_to_cursor(u32 buttons); + +#define PLAT_BUTTON_COUNT 17 +extern u32 button_plat_mask_to_config[PLAT_BUTTON_COUNT]; + +void *fb_flip_screen(void); +void fb_set_mode(int w, int h, int buffers, int scale, int filter); +void fb_wait_vsync(void); diff --git a/video.c b/video.c index 59f3e69..a33accf 100644 --- a/video.c +++ b/video.c @@ -102,6 +102,16 @@ const u32 screen_pitch = 320; #define get_screen_pitch() \ screen_pitch \ +#elif defined(PND_BUILD) + +static u16 *screen_pixels = NULL; + +#define get_screen_pixels() \ + screen_pixels \ + +#define get_screen_pitch() \ + resolution_width \ + #else #ifdef GP2X_BUILD @@ -3392,6 +3402,13 @@ no_clean: screen_pixels = (u16 *)gpsp_gp2x_screen + screen_offset; } +#elif defined(PND_BUILD) + +void flip_screen() +{ + screen_pixels = fb_flip_screen(); +} + #else #define integer_scale_copy_2() \ @@ -3601,7 +3618,7 @@ void init_video() GE_CMD(NOP, 0); } -#elif defined(WIZ_BUILD) +#elif defined(WIZ_BUILD) || defined(PND_BUILD) void init_video() { @@ -3796,6 +3813,42 @@ void clear_screen(u16 color) *p++ = col; } +#elif defined(PND_BUILD) + +void video_resolution_large() +{ + resolution_width = 400; + resolution_height = 272; + + fb_set_mode(400, 272, 1, 15, screen_filter); + flip_screen(); + clear_screen(0); +} + +void video_resolution_small() +{ + resolution_width = 240; + resolution_height = 160; + + fb_set_mode(240, 160, 4, screen_scale, screen_filter); + flip_screen(); + clear_screen(0); +} + +void set_gba_resolution(video_scale_type scale) +{ + screen_scale = scale; +} + +void clear_screen(u16 color) +{ + u32 col = ((u32)color << 16) | color; + u32 *p = (u32 *)get_screen_pixels(); + int c = resolution_width * resolution_height / 2; + while (c-- > 0) + *p++ = col; +} + #else void video_resolution_large() -- 2.39.2