Mercurial > sdl-ios-xcode
changeset 70:f590dd383b5d
Added Linux PlayStation 2 Graphics Synthesizer support
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Sat, 16 Jun 2001 03:17:45 +0000 |
parents | 280ff3af2ecc |
children | cb4d780b41b6 |
files | configure.in docs.html src/video/ps2gs/.cvsignore src/video/ps2gs/Makefile.am src/video/ps2gs/SDL_gsevents.c src/video/ps2gs/SDL_gsevents_c.h src/video/ps2gs/SDL_gskeys.h src/video/ps2gs/SDL_gsmouse.c src/video/ps2gs/SDL_gsmouse_c.h src/video/ps2gs/SDL_gsvideo.c src/video/ps2gs/SDL_gsvideo.h src/video/ps2gs/SDL_gsyuv.c src/video/ps2gs/SDL_gsyuv_c.h |
diffstat | 13 files changed, 2582 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.in Sat Jun 16 02:48:39 2001 +0000 +++ b/configure.in Sat Jun 16 03:17:45 2001 +0000 @@ -666,6 +666,32 @@ fi } +dnl See if we're running on PlayStation 2 hardware +CheckPS2GS() +{ +dnl AC_ARG_ENABLE(video-ps2gs, +dnl[ --enable-video-ps2gs use PlayStation 2 GS video driver [default=yes]], +dnl , enable_video_ps2gs=yes) +enable_video_ps2gs=yes + if test x$enable_video = xyes -a x$enable_video_ps2gs = xyes; then + dnl AC_MSG_CHECKING(for PlayStation 2 GS support) + video_ps2gs=no + AC_TRY_COMPILE([ + #include <linux/ps2/dev.h> + #include <linux/ps2/gs.h> + ],[ + ],[ + video_ps2gs=yes + ]) + dnl AC_MSG_RESULT($video_ps2gs) + if test x$video_ps2gs = xyes; then + CFLAGS="$CFLAGS -DENABLE_PS2GS" + VIDEO_SUBDIRS="$VIDEO_SUBDIRS ps2gs" + VIDEO_DRIVERS="$VIDEO_DRIVERS ps2gs/libvideo_ps2gs.la" + fi + fi +} + dnl Find the GGI includes CheckGGI() { @@ -1111,6 +1137,7 @@ CheckNANOX CheckDGA CheckFBCON + CheckPS2GS CheckGGI CheckSVGA CheckAAlib @@ -2011,6 +2038,7 @@ src/video/dga/Makefile src/video/nanox/Makefile src/video/fbcon/Makefile +src/video/ps2gs/Makefile src/video/ggi/Makefile src/video/maccommon/Makefile src/video/macdsp/Makefile
--- a/docs.html Sat Jun 16 02:48:39 2001 +0000 +++ b/docs.html Sat Jun 16 03:17:45 2001 +0000 @@ -16,6 +16,7 @@ Major changes since SDL 1.0.0: </H2> <UL> + <LI> 1.2.1: Added Linux PlayStation 2 Graphics Synthesizer support <LI> 1.2.1: Added an audio driver that writes to disk (thanks Ryan!) <LI> 1.2.1: Mouse wheel sends mouse button (4/5) events on Windows <LI> 1.2.1: Added MacOS X Project Builder projects (thanks Darrell!)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/.cvsignore Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,6 @@ +Makefile.in +Makefile +.libs +*.o +*.lo +*.la
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/Makefile.am Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,17 @@ + +## Makefile.am for SDL using the framebuffer console video driver + +noinst_LTLIBRARIES = libvideo_ps2gs.la +libvideo_ps2gs_la_SOURCES = $(PS2GS_SRCS) + +# The SDL framebuffer console video driver sources +PS2GS_SRCS = \ + SDL_gsevents.c \ + SDL_gsevents_c.h \ + SDL_gskeys.h \ + SDL_gsmouse.c \ + SDL_gsmouse_c.h \ + SDL_gsvideo.c \ + SDL_gsvideo.h \ + SDL_gsyuv.c \ + SDL_gsyuv_c.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/SDL_gsevents.c Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,983 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +/* Handle the event stream, converting console events into SDL events */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <limits.h> + +/* For parsing /proc */ +#include <dirent.h> +#include <ctype.h> + +#include <linux/vt.h> +#include <linux/kd.h> +#include <linux/keyboard.h> + +#include "SDL.h" +#include "SDL_mutex.h" +#include "SDL_sysevents.h" +#include "SDL_sysvideo.h" +#include "SDL_events_c.h" +#include "SDL_gsvideo.h" +#include "SDL_gsevents_c.h" +#include "SDL_gskeys.h" + +#ifndef GPM_NODE_FIFO +#define GPM_NODE_FIFO "/dev/gpmdata" +#endif + +/* The translation tables from a console scancode to a SDL keysym */ +#define NUM_VGAKEYMAPS (1<<KG_CAPSSHIFT) +static Uint16 vga_keymap[NUM_VGAKEYMAPS][NR_KEYS]; +static SDLKey keymap[128]; +static Uint16 keymap_temp[128]; /* only used at startup */ +static SDL_keysym *TranslateKey(int scancode, SDL_keysym *keysym); + +/* Ugh, we have to duplicate the kernel's keysym mapping code... + Oh, it's not so bad. :-) + + FIXME: Add keyboard LED handling code + */ +static void GS_vgainitkeymaps(int fd) +{ + struct kbentry entry; + int map, i; + + /* Don't do anything if we are passed a closed keyboard */ + if ( fd < 0 ) { + return; + } + + /* Load all the keysym mappings */ + for ( map=0; map<NUM_VGAKEYMAPS; ++map ) { + memset(vga_keymap[map], 0, NR_KEYS*sizeof(Uint16)); + for ( i=0; i<NR_KEYS; ++i ) { + entry.kb_table = map; + entry.kb_index = i; + if ( ioctl(fd, KDGKBENT, &entry) == 0 ) { + /* fill keytemp. This replaces SDL_fbkeys.h */ + if ( (map == 0) && (i<128) ) { + keymap_temp[i] = entry.kb_value; + } + /* The "Enter" key is a special case */ + if ( entry.kb_value == K_ENTER ) { + entry.kb_value = K(KT_ASCII,13); + } + /* Handle numpad specially as well */ + if ( KTYP(entry.kb_value) == KT_PAD ) { + switch ( entry.kb_value ) { + case K_P0: + case K_P1: + case K_P2: + case K_P3: + case K_P4: + case K_P5: + case K_P6: + case K_P7: + case K_P8: + case K_P9: + vga_keymap[map][i]=entry.kb_value; + vga_keymap[map][i]+= '0'; + break; + case K_PPLUS: + vga_keymap[map][i]=K(KT_ASCII,'+'); + break; + case K_PMINUS: + vga_keymap[map][i]=K(KT_ASCII,'-'); + break; + case K_PSTAR: + vga_keymap[map][i]=K(KT_ASCII,'*'); + break; + case K_PSLASH: + vga_keymap[map][i]=K(KT_ASCII,'/'); + break; + case K_PENTER: + vga_keymap[map][i]=K(KT_ASCII,'\r'); + break; + case K_PCOMMA: + vga_keymap[map][i]=K(KT_ASCII,','); + break; + case K_PDOT: + vga_keymap[map][i]=K(KT_ASCII,'.'); + break; + default: + break; + } + } + /* Do the normal key translation */ + if ( (KTYP(entry.kb_value) == KT_LATIN) || + (KTYP(entry.kb_value) == KT_ASCII) || + (KTYP(entry.kb_value) == KT_LETTER) ) { + vga_keymap[map][i] = entry.kb_value; + } + } + } + } +} + +int GS_InGraphicsMode(_THIS) +{ + return((keyboard_fd >= 0) && (saved_kbd_mode >= 0)); +} + +int GS_EnterGraphicsMode(_THIS) +{ + struct termios keyboard_termios; + + /* Set medium-raw keyboard mode */ + if ( (keyboard_fd >= 0) && !GS_InGraphicsMode(this) ) { + + /* Switch to the correct virtual terminal */ + if ( current_vt > 0 ) { + struct vt_stat vtstate; + + if ( ioctl(keyboard_fd, VT_GETSTATE, &vtstate) == 0 ) { + saved_vt = vtstate.v_active; + } + if ( ioctl(keyboard_fd, VT_ACTIVATE, current_vt) == 0 ) { + ioctl(keyboard_fd, VT_WAITACTIVE, current_vt); + } + } + + /* Set the terminal input mode */ + if ( tcgetattr(keyboard_fd, &saved_kbd_termios) < 0 ) { + SDL_SetError("Unable to get terminal attributes"); + if ( keyboard_fd > 0 ) { + close(keyboard_fd); + } + keyboard_fd = -1; + return(-1); + } + if ( ioctl(keyboard_fd, KDGKBMODE, &saved_kbd_mode) < 0 ) { + SDL_SetError("Unable to get current keyboard mode"); + if ( keyboard_fd > 0 ) { + close(keyboard_fd); + } + keyboard_fd = -1; + return(-1); + } + keyboard_termios = saved_kbd_termios; + keyboard_termios.c_lflag &= ~(ICANON | ECHO | ISIG); + keyboard_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); + keyboard_termios.c_cc[VMIN] = 0; + keyboard_termios.c_cc[VTIME] = 0; + if (tcsetattr(keyboard_fd, TCSAFLUSH, &keyboard_termios) < 0) { + GS_CloseKeyboard(this); + SDL_SetError("Unable to set terminal attributes"); + return(-1); + } + /* This will fail if we aren't root or this isn't our tty */ + if ( ioctl(keyboard_fd, KDSKBMODE, K_MEDIUMRAW) < 0 ) { + GS_CloseKeyboard(this); + SDL_SetError("Unable to set keyboard in raw mode"); + return(-1); + } + if ( ioctl(keyboard_fd, KDSETMODE, KD_GRAPHICS) < 0 ) { + GS_CloseKeyboard(this); + SDL_SetError("Unable to set keyboard in graphics mode"); + return(-1); + } + } + return(keyboard_fd); +} + +void GS_LeaveGraphicsMode(_THIS) +{ + if ( GS_InGraphicsMode(this) ) { + ioctl(keyboard_fd, KDSETMODE, KD_TEXT); + ioctl(keyboard_fd, KDSKBMODE, saved_kbd_mode); + tcsetattr(keyboard_fd, TCSAFLUSH, &saved_kbd_termios); + saved_kbd_mode = -1; + + /* Head back over to the original virtual terminal */ + if ( saved_vt > 0 ) { + ioctl(keyboard_fd, VT_ACTIVATE, saved_vt); + } + } +} + +void GS_CloseKeyboard(_THIS) +{ + if ( keyboard_fd >= 0 ) { + GS_LeaveGraphicsMode(this); + if ( keyboard_fd > 0 ) { + close(keyboard_fd); + } + } + keyboard_fd = -1; +} + +int GS_OpenKeyboard(_THIS) +{ + /* Open only if not already opened */ + if ( keyboard_fd < 0 ) { + char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; + char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL }; + int i, tty0_fd; + + /* Try to query for a free virtual terminal */ + tty0_fd = -1; + for ( i=0; tty0[i] && (tty0_fd < 0); ++i ) { + tty0_fd = open(tty0[i], O_WRONLY, 0); + } + if ( tty0_fd < 0 ) { + tty0_fd = dup(0); /* Maybe stdin is a VT? */ + } + ioctl(tty0_fd, VT_OPENQRY, ¤t_vt); + close(tty0_fd); + if ( (geteuid() == 0) && (current_vt > 0) ) { + for ( i=0; vcs[i] && (keyboard_fd < 0); ++i ) { + char vtpath[12]; + + sprintf(vtpath, vcs[i], current_vt); + keyboard_fd = open(vtpath, O_RDWR, 0); +#ifdef DEBUG_KEYBOARD + fprintf(stderr, "vtpath = %s, fd = %d\n", + vtpath, keyboard_fd); +#endif /* DEBUG_KEYBOARD */ + + /* This needs to be our controlling tty + so that the kernel ioctl() calls work + */ + if ( keyboard_fd >= 0 ) { + tty0_fd = open("/dev/tty", O_RDWR, 0); + if ( tty0_fd >= 0 ) { + ioctl(tty0_fd, TIOCNOTTY, 0); + close(tty0_fd); + } + } + } + } + if ( keyboard_fd < 0 ) { + /* Last resort, maybe our tty is a usable VT */ + current_vt = 0; + keyboard_fd = open("/dev/tty", O_RDWR); + } +#ifdef DEBUG_KEYBOARD + fprintf(stderr, "Current VT: %d\n", current_vt); +#endif + saved_kbd_mode = -1; + + /* Make sure that our input is a console terminal */ + { int dummy; + if ( ioctl(keyboard_fd, KDGKBMODE, &dummy) < 0 ) { + close(keyboard_fd); + keyboard_fd = -1; + SDL_SetError("Unable to open a console terminal"); + } + } + + /* Set up keymap */ + GS_vgainitkeymaps(keyboard_fd); + } + return(keyboard_fd); +} + +static enum { + MOUSE_NONE = -1, + MOUSE_GPM, /* Note: GPM uses the MSC protocol */ + MOUSE_PS2, + MOUSE_IMPS2, + MOUSE_MS, + MOUSE_BM, + NUM_MOUSE_DRVS +} mouse_drv = MOUSE_NONE; + +void GS_CloseMouse(_THIS) +{ + if ( mouse_fd > 0 ) { + close(mouse_fd); + } + mouse_fd = -1; +} + +/* Returns processes listed in /proc with the desired name */ +static int find_pid(DIR *proc, const char *wanted_name) +{ + struct dirent *entry; + int pid; + + /* First scan proc for the gpm process */ + pid = 0; + while ( (pid == 0) && ((entry=readdir(proc)) != NULL) ) { + if ( isdigit(entry->d_name[0]) ) { + FILE *status; + char path[PATH_MAX]; + char name[PATH_MAX]; + + sprintf(path, "/proc/%s/status", entry->d_name); + status=fopen(path, "r"); + if ( status ) { + name[0] = '\0'; + fscanf(status, "Name: %s", name); + if ( strcmp(name, wanted_name) == 0 ) { + pid = atoi(entry->d_name); + } + fclose(status); + } + } + } + return pid; +} + +/* Returns true if /dev/gpmdata is being written to by gpm */ +static int gpm_available(void) +{ + int available; + DIR *proc; + int pid; + int cmdline, len, arglen; + char path[PATH_MAX]; + char args[PATH_MAX], *arg; + + /* Don't bother looking if the fifo isn't there */ + if ( access(GPM_NODE_FIFO, F_OK) < 0 ) { + return(0); + } + + available = 0; + proc = opendir("/proc"); + if ( proc ) { + while ( (pid=find_pid(proc, "gpm")) > 0 ) { + sprintf(path, "/proc/%d/cmdline", pid); + cmdline = open(path, O_RDONLY, 0); + if ( cmdline >= 0 ) { + len = read(cmdline, args, sizeof(args)); + arg = args; + while ( len > 0 ) { + if ( strcmp(arg, "-R") == 0 ) { + available = 1; + } + arglen = strlen(arg)+1; + len -= arglen; + arg += arglen; + } + close(cmdline); + } + } + closedir(proc); + } + return available; +} + + +/* rcg06112001 Set up IMPS/2 mode, if possible. This gives + * us access to the mousewheel, etc. Returns zero if + * writes to device failed, but you still need to query the + * device to see which mode it's actually in. + */ +static int set_imps2_mode(int fd) +{ + /* If you wanted to control the mouse mode (and we do :) ) ... + Set IMPS/2 protocol: + {0xf3,200,0xf3,100,0xf3,80} + Reset mouse device: + {0xFF} + */ + Uint8 set_imps2[] = {0xf3, 200, 0xf3, 100, 0xf3, 80}; + Uint8 reset = 0xff; + fd_set fdset; + struct timeval tv; + int retval = 0; + + if ( write(fd, &set_imps2, sizeof(set_imps2)) == sizeof(set_imps2) ) { + if (write(fd, &reset, sizeof (reset)) == sizeof (reset) ) { + retval = 1; + } + } + + /* Get rid of any chatter from the above */ + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + tv.tv_sec = 0; + tv.tv_usec = 0; + while ( select(fd+1, &fdset, 0, 0, &tv) > 0 ) { + char temp[32]; + read(fd, temp, sizeof(temp)); + } + + return retval; +} + + +/* Returns true if the mouse uses the IMPS/2 protocol */ +static int detect_imps2(int fd) +{ + int imps2; + + imps2 = 0; + + if ( getenv("SDL_MOUSEDEV_IMPS2") ) { + imps2 = 1; + } + if ( ! imps2 ) { + Uint8 query_ps2 = 0xF2; + fd_set fdset; + struct timeval tv; + + /* Get rid of any mouse motion noise */ + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + tv.tv_sec = 0; + tv.tv_usec = 0; + while ( select(fd+1, &fdset, 0, 0, &tv) > 0 ) { + char temp[32]; + read(fd, temp, sizeof(temp)); + } + + /* Query for the type of mouse protocol */ + if ( write(fd, &query_ps2, sizeof (query_ps2)) == sizeof (query_ps2)) { + Uint8 ch = 0; + + /* Get the mouse protocol response */ + do { + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + tv.tv_sec = 1; + tv.tv_usec = 0; + if ( select(fd+1, &fdset, 0, 0, &tv) < 1 ) { + break; + } + } while ( (read(fd, &ch, sizeof (ch)) == sizeof (ch)) && + ((ch == 0xFA) || (ch == 0xAA)) ); + + /* Experimental values (Logitech wheelmouse) */ +#ifdef DEBUG_MOUSE +fprintf(stderr, "Last mouse mode: 0x%x\n", ch); +#endif + if ( ch == 3 ) { + imps2 = 1; + } + } + } + return imps2; +} + +int GS_OpenMouse(_THIS) +{ + int i; + const char *mousedev; + const char *mousedrv; + + mousedrv = getenv("SDL_MOUSEDRV"); + mousedev = getenv("SDL_MOUSEDEV"); + mouse_fd = -1; + + /* STD MICE */ + + if ( mousedev == NULL ) { + /* FIXME someday... allow multiple mice in this driver */ + char *ps2mice[] = { + "/dev/input/mice", "/dev/usbmouse", "/dev/psaux", NULL + }; + /* First try to use GPM in repeater mode */ + if ( mouse_fd < 0 ) { + if ( gpm_available() ) { + mouse_fd = open(GPM_NODE_FIFO, O_RDONLY, 0); + if ( mouse_fd >= 0 ) { +#ifdef DEBUG_MOUSE +fprintf(stderr, "Using GPM mouse\n"); +#endif + mouse_drv = MOUSE_GPM; + } + } + } + /* Now try to use a modern PS/2 mouse */ + for ( i=0; (mouse_fd < 0) && ps2mice[i]; ++i ) { + mouse_fd = open(ps2mice[i], O_RDWR, 0); + if (mouse_fd < 0) { + mouse_fd = open(ps2mice[i], O_RDONLY, 0); + } + if (mouse_fd >= 0) { + /* rcg06112001 Attempt to set IMPS/2 mode */ + if ( i == 0 ) { + set_imps2_mode(mouse_fd); + } + if (detect_imps2(mouse_fd)) { +#ifdef DEBUG_MOUSE +fprintf(stderr, "Using IMPS2 mouse\n"); +#endif + mouse_drv = MOUSE_IMPS2; + } else { + mouse_drv = MOUSE_PS2; +#ifdef DEBUG_MOUSE +fprintf(stderr, "Using PS2 mouse\n"); +#endif + } + } + } + /* Next try to use a PPC ADB port mouse */ + if ( mouse_fd < 0 ) { + mouse_fd = open("/dev/adbmouse", O_RDONLY, 0); + if ( mouse_fd >= 0 ) { +#ifdef DEBUG_MOUSE +fprintf(stderr, "Using ADB mouse\n"); +#endif + mouse_drv = MOUSE_BM; + } + } + } + /* Default to a serial Microsoft mouse */ + if ( mouse_fd < 0 ) { + if ( mousedev == NULL ) { + mousedev = "/dev/mouse"; + } + mouse_fd = open(mousedev, O_RDONLY, 0); + if ( mouse_fd >= 0 ) { + struct termios mouse_termios; + + /* Set the sampling speed to 1200 baud */ + tcgetattr(mouse_fd, &mouse_termios); + mouse_termios.c_iflag = IGNBRK | IGNPAR; + mouse_termios.c_oflag = 0; + mouse_termios.c_lflag = 0; + mouse_termios.c_line = 0; + mouse_termios.c_cc[VTIME] = 0; + mouse_termios.c_cc[VMIN] = 1; + mouse_termios.c_cflag = CREAD | CLOCAL | HUPCL; + mouse_termios.c_cflag |= CS8; + mouse_termios.c_cflag |= B1200; + tcsetattr(mouse_fd, TCSAFLUSH, &mouse_termios); +#ifdef DEBUG_MOUSE +fprintf(stderr, "Using Microsoft mouse on %s\n", mousedev); +#endif + mouse_drv = MOUSE_MS; + } + } + if ( mouse_fd < 0 ) { + mouse_drv = MOUSE_NONE; + } + return(mouse_fd); +} + +static int posted = 0; + +void GS_vgamousecallback(int button, int dx, int dy) +{ + int button_1, button_3; + int button_state; + int state_changed; + int i; + Uint8 state; + + if ( dx || dy ) { + posted += SDL_PrivateMouseMotion(0, 1, dx, dy); + } + + /* Swap button 1 and 3 */ + button_1 = (button & 0x04) >> 2; + button_3 = (button & 0x01) << 2; + button &= ~0x05; + button |= (button_1|button_3); + + /* See what changed */ + button_state = SDL_GetMouseState(NULL, NULL); + state_changed = button_state ^ button; + for ( i=0; i<8; ++i ) { + if ( state_changed & (1<<i) ) { + if ( button & (1<<i) ) { + state = SDL_PRESSED; + } else { + state = SDL_RELEASED; + } + posted += SDL_PrivateMouseButton(state, i+1, 0, 0); + } + } +} + +/* For now, use GPM, PS/2, and MS protocols + Driver adapted from the SVGAlib mouse driver code (taken from gpm, etc.) + */ +static void handle_mouse(_THIS) +{ + static int start = 0; + static unsigned char mousebuf[BUFSIZ]; + int i, nread; + int button = 0; + int dx = 0, dy = 0; + int packetsize = 0; + + /* Figure out the mouse packet size */ + switch (mouse_drv) { + case MOUSE_NONE: + /* Ack! */ + read(mouse_fd, mousebuf, BUFSIZ); + return; + case MOUSE_GPM: + packetsize = 5; + break; + case MOUSE_IMPS2: + packetsize = 4; + break; + case MOUSE_PS2: + case MOUSE_MS: + case MOUSE_BM: + packetsize = 3; + break; + case NUM_MOUSE_DRVS: + /* Uh oh.. */ + packetsize = 0; + break; + } + + /* Read as many packets as possible */ + nread = read(mouse_fd, &mousebuf[start], BUFSIZ-start); + if ( nread < 0 ) { + return; + } + nread += start; +#ifdef DEBUG_MOUSE + fprintf(stderr, "Read %d bytes from mouse, start = %d\n", nread, start); +#endif + for ( i=0; i<(nread-(packetsize-1)); i += packetsize ) { + switch (mouse_drv) { + case MOUSE_NONE: + break; + case MOUSE_GPM: + /* GPM protocol has 0x80 in high byte */ + if ( (mousebuf[i] & 0xF8) != 0x80 ) { + /* Go to next byte */ + i -= (packetsize-1); + continue; + } + /* Get current mouse state */ + button = (~mousebuf[i]) & 0x07; + dx = (signed char)(mousebuf[i+1]) + + (signed char)(mousebuf[i+3]); + dy = -((signed char)(mousebuf[i+2]) + + (signed char)(mousebuf[i+4])); + break; + case MOUSE_PS2: + /* PS/2 protocol has nothing in high byte */ + if ( (mousebuf[i] & 0xC0) != 0 ) { + /* Go to next byte */ + i -= (packetsize-1); + continue; + } + /* Get current mouse state */ + button = (mousebuf[i] & 0x04) >> 1 | /*Middle*/ + (mousebuf[i] & 0x02) >> 1 | /*Right*/ + (mousebuf[i] & 0x01) << 2; /*Left*/ + dx = (mousebuf[i] & 0x10) ? + mousebuf[i+1] - 256 : mousebuf[i+1]; + dy = (mousebuf[i] & 0x20) ? + -(mousebuf[i+2] - 256) : -mousebuf[i+2]; + break; + case MOUSE_IMPS2: + /* Get current mouse state */ + button = (mousebuf[i] & 0x04) >> 1 | /*Middle*/ + (mousebuf[i] & 0x02) >> 1 | /*Right*/ + (mousebuf[i] & 0x01) << 2 | /*Left*/ + (mousebuf[i] & 0x40) >> 3 | /* 4 */ + (mousebuf[i] & 0x80) >> 3; /* 5 */ + dx = (mousebuf[i] & 0x10) ? + mousebuf[i+1] - 256 : mousebuf[i+1]; + dy = (mousebuf[i] & 0x20) ? + -(mousebuf[i+2] - 256) : -mousebuf[i+2]; + switch (mousebuf[i+3]&0x0F) { + case 0x0E: /* DX = +1 */ + case 0x02: /* DX = -1 */ + break; + case 0x0F: /* DY = +1 (map button 4) */ + button |= (1<<3); + break; + case 0x01: /* DY = -1 (map button 5) */ + button |= (1<<4); + break; + } + break; + case MOUSE_MS: + /* Microsoft protocol has 0x40 in high byte */ + if ( (mousebuf[i] & 0x40) != 0x40 ) { + /* Go to next byte */ + i -= (packetsize-1); + continue; + } + /* Get current mouse state */ + button = ((mousebuf[i] & 0x20) >> 3) | + ((mousebuf[i] & 0x10) >> 4); + dx = (signed char)(((mousebuf[i] & 0x03) << 6) | + (mousebuf[i + 1] & 0x3F)); + dy = (signed char)(((mousebuf[i] & 0x0C) << 4) | + (mousebuf[i + 2] & 0x3F)); + break; + case MOUSE_BM: + /* BusMouse protocol has 0xF8 in high byte */ + if ( (mousebuf[i] & 0xF8) != 0x80 ) { + /* Go to next byte */ + i -= (packetsize-1); + continue; + } + /* Get current mouse state */ + button = (~mousebuf[i]) & 0x07; + dx = (signed char)mousebuf[i+1]; + dy = -(signed char)mousebuf[i+2]; + break; + case NUM_MOUSE_DRVS: + /* Uh oh.. */ + dx = 0; + dy = 0; + break; + } + GS_vgamousecallback(button, dx, dy); + } + if ( i < nread ) { + memcpy(mousebuf, &mousebuf[i], (nread-i)); + start = (nread-i); + } else { + start = 0; + } + return; +} + +static void handle_keyboard(_THIS) +{ + unsigned char keybuf[BUFSIZ]; + int i, nread; + int pressed; + int scancode; + SDL_keysym keysym; + + nread = read(keyboard_fd, keybuf, BUFSIZ); + for ( i=0; i<nread; ++i ) { + scancode = keybuf[i] & 0x7F; + if ( keybuf[i] & 0x80 ) { + pressed = SDL_RELEASED; + } else { + pressed = SDL_PRESSED; + } + TranslateKey(scancode, &keysym); + posted += SDL_PrivateKeyboard(pressed, &keysym); + } +} + +void GS_PumpEvents(_THIS) +{ + fd_set fdset; + int max_fd; + static struct timeval zero; + + do { + posted = 0; + + FD_ZERO(&fdset); + max_fd = 0; + if ( keyboard_fd >= 0 ) { + FD_SET(keyboard_fd, &fdset); + if ( max_fd < keyboard_fd ) { + max_fd = keyboard_fd; + } + } + if ( mouse_fd >= 0 ) { + FD_SET(mouse_fd, &fdset); + if ( max_fd < mouse_fd ) { + max_fd = mouse_fd; + } + } + if ( select(max_fd+1, &fdset, NULL, NULL, &zero) > 0 ) { + if ( keyboard_fd >= 0 ) { + if ( FD_ISSET(keyboard_fd, &fdset) ) { + handle_keyboard(this); + } + } + if ( mouse_fd >= 0 ) { + if ( FD_ISSET(mouse_fd, &fdset) ) { + handle_mouse(this); + } + } + } + } while ( posted ); +} + +void GS_InitOSKeymap(_THIS) +{ + int i; + + /* Initialize the Linux key translation table */ + + /* First get the ascii keys and others not well handled */ + for (i=0; i<SDL_TABLESIZE(keymap); ++i) { + switch(i) { + /* These aren't handled by the x86 kernel keymapping (?) */ + case SCANCODE_PRINTSCREEN: + keymap[i] = SDLK_PRINT; + break; + case SCANCODE_BREAK: + keymap[i] = SDLK_BREAK; + break; + case SCANCODE_BREAK_ALTERNATIVE: + keymap[i] = SDLK_PAUSE; + break; + case SCANCODE_LEFTSHIFT: + keymap[i] = SDLK_LSHIFT; + break; + case SCANCODE_RIGHTSHIFT: + keymap[i] = SDLK_RSHIFT; + break; + case SCANCODE_LEFTCONTROL: + keymap[i] = SDLK_LCTRL; + break; + case SCANCODE_RIGHTCONTROL: + keymap[i] = SDLK_RCTRL; + break; + case SCANCODE_RIGHTWIN: + keymap[i] = SDLK_RSUPER; + break; + case SCANCODE_LEFTWIN: + keymap[i] = SDLK_LSUPER; + break; + case 127: + keymap[i] = SDLK_MENU; + break; + /* this should take care of all standard ascii keys */ + default: + keymap[i] = KVAL(vga_keymap[0][i]); + break; + } + } + for (i=0; i<SDL_TABLESIZE(keymap); ++i) { + switch(keymap_temp[i]) { + case K_F1: keymap[i] = SDLK_F1; break; + case K_F2: keymap[i] = SDLK_F2; break; + case K_F3: keymap[i] = SDLK_F3; break; + case K_F4: keymap[i] = SDLK_F4; break; + case K_F5: keymap[i] = SDLK_F5; break; + case K_F6: keymap[i] = SDLK_F6; break; + case K_F7: keymap[i] = SDLK_F7; break; + case K_F8: keymap[i] = SDLK_F8; break; + case K_F9: keymap[i] = SDLK_F9; break; + case K_F10: keymap[i] = SDLK_F10; break; + case K_F11: keymap[i] = SDLK_F11; break; + case K_F12: keymap[i] = SDLK_F12; break; + + case K_DOWN: keymap[i] = SDLK_DOWN; break; + case K_LEFT: keymap[i] = SDLK_LEFT; break; + case K_RIGHT: keymap[i] = SDLK_RIGHT; break; + case K_UP: keymap[i] = SDLK_UP; break; + + case K_P0: keymap[i] = SDLK_KP0; break; + case K_P1: keymap[i] = SDLK_KP1; break; + case K_P2: keymap[i] = SDLK_KP2; break; + case K_P3: keymap[i] = SDLK_KP3; break; + case K_P4: keymap[i] = SDLK_KP4; break; + case K_P5: keymap[i] = SDLK_KP5; break; + case K_P6: keymap[i] = SDLK_KP6; break; + case K_P7: keymap[i] = SDLK_KP7; break; + case K_P8: keymap[i] = SDLK_KP8; break; + case K_P9: keymap[i] = SDLK_KP9; break; + case K_PPLUS: keymap[i] = SDLK_KP_PLUS; break; + case K_PMINUS: keymap[i] = SDLK_KP_MINUS; break; + case K_PSTAR: keymap[i] = SDLK_KP_MULTIPLY; break; + case K_PSLASH: keymap[i] = SDLK_KP_DIVIDE; break; + case K_PENTER: keymap[i] = SDLK_KP_ENTER; break; + case K_PDOT: keymap[i] = SDLK_KP_PERIOD; break; + + case K_SHIFT: if ( keymap[i] != SDLK_RSHIFT ) + keymap[i] = SDLK_LSHIFT; + break; + case K_SHIFTL: keymap[i] = SDLK_LSHIFT; break; + case K_SHIFTR: keymap[i] = SDLK_RSHIFT; break; + case K_CTRL: if ( keymap[i] != SDLK_RCTRL ) + keymap[i] = SDLK_LCTRL; + break; + case K_CTRLL: keymap[i] = SDLK_LCTRL; break; + case K_CTRLR: keymap[i] = SDLK_RCTRL; break; + case K_ALT: keymap[i] = SDLK_LALT; break; + case K_ALTGR: keymap[i] = SDLK_RALT; break; + + case K_INSERT: keymap[i] = SDLK_INSERT; break; + case K_REMOVE: keymap[i] = SDLK_DELETE; break; + case K_PGUP: keymap[i] = SDLK_PAGEUP; break; + case K_PGDN: keymap[i] = SDLK_PAGEDOWN; break; + case K_FIND: keymap[i] = SDLK_HOME; break; + case K_SELECT: keymap[i] = SDLK_END; break; + + case K_NUM: keymap[i] = SDLK_NUMLOCK; break; + case K_CAPS: keymap[i] = SDLK_CAPSLOCK; break; + + case K_F13: keymap[i] = SDLK_PRINT; break; + case K_HOLD: keymap[i] = SDLK_SCROLLOCK; break; + case K_PAUSE: keymap[i] = SDLK_PAUSE; break; + + case 127: keymap[i] = SDLK_BACKSPACE; break; + + default: break; + } + } +} + +static SDL_keysym *TranslateKey(int scancode, SDL_keysym *keysym) +{ + /* Set the keysym information */ + keysym->scancode = scancode; + keysym->sym = keymap[scancode]; + keysym->mod = KMOD_NONE; + + /* If UNICODE is on, get the UNICODE value for the key */ + keysym->unicode = 0; + if ( SDL_TranslateUNICODE ) { + int map; + SDLMod modstate; + + modstate = SDL_GetModState(); + map = 0; + if ( modstate & KMOD_SHIFT ) { + map |= (1<<KG_SHIFT); + } + if ( modstate & KMOD_CTRL ) { + map |= (1<<KG_CTRL); + } + if ( modstate & KMOD_ALT ) { + map |= (1<<KG_ALT); + } + if ( modstate & KMOD_MODE ) { + map |= (1<<KG_ALTGR); + } + if ( KTYP(vga_keymap[map][scancode]) == KT_LETTER ) { + if ( modstate & KMOD_CAPS ) { + map ^= (1<<KG_SHIFT); + } + } + if ( KTYP(vga_keymap[map][scancode]) == KT_PAD ) { + if ( modstate & KMOD_NUM ) { + keysym->unicode=KVAL(vga_keymap[map][scancode]); + } + } else { + keysym->unicode = KVAL(vga_keymap[map][scancode]); + } + } + return(keysym); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/SDL_gsevents_c.h Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,42 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +#include "SDL_gsvideo.h" + +/* Variables and functions exported by SDL_sysevents.c to other parts + of the native video subsystem (SDL_sysvideo.c) +*/ +extern int GS_OpenKeyboard(_THIS); +extern void GS_CloseKeyboard(_THIS); +extern int GS_OpenMouse(_THIS); +extern void GS_CloseMouse(_THIS); +extern int GS_EnterGraphicsMode(_THIS); +extern int GS_InGraphicsMode(_THIS); +extern void GS_LeaveGraphicsMode(_THIS); + +extern void GS_InitOSKeymap(_THIS); +extern void GS_PumpEvents(_THIS);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/SDL_gskeys.h Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,139 @@ + +/* Scancodes for the Linux framebuffer console + - Taken with thanks from SVGAlib 1.4.0 +*/ + +#define SCANCODE_ESCAPE 1 + +#define SCANCODE_1 2 +#define SCANCODE_2 3 +#define SCANCODE_3 4 +#define SCANCODE_4 5 +#define SCANCODE_5 6 +#define SCANCODE_6 7 +#define SCANCODE_7 8 +#define SCANCODE_8 9 +#define SCANCODE_9 10 +#define SCANCODE_0 11 + +#define SCANCODE_MINUS 12 +#define SCANCODE_EQUAL 13 + +#define SCANCODE_BACKSPACE 14 +#define SCANCODE_TAB 15 + +#define SCANCODE_Q 16 +#define SCANCODE_W 17 +#define SCANCODE_E 18 +#define SCANCODE_R 19 +#define SCANCODE_T 20 +#define SCANCODE_Y 21 +#define SCANCODE_U 22 +#define SCANCODE_I 23 +#define SCANCODE_O 24 +#define SCANCODE_P 25 +#define SCANCODE_BRACKET_LEFT 26 +#define SCANCODE_BRACKET_RIGHT 27 + +#define SCANCODE_ENTER 28 + +#define SCANCODE_LEFTCONTROL 29 + +#define SCANCODE_A 30 +#define SCANCODE_S 31 +#define SCANCODE_D 32 +#define SCANCODE_F 33 +#define SCANCODE_G 34 +#define SCANCODE_H 35 +#define SCANCODE_J 36 +#define SCANCODE_K 37 +#define SCANCODE_L 38 +#define SCANCODE_SEMICOLON 39 +#define SCANCODE_APOSTROPHE 40 +#define SCANCODE_GRAVE 41 + +#define SCANCODE_LEFTSHIFT 42 +#define SCANCODE_BACKSLASH 43 + +#define SCANCODE_Z 44 +#define SCANCODE_X 45 +#define SCANCODE_C 46 +#define SCANCODE_V 47 +#define SCANCODE_B 48 +#define SCANCODE_N 49 +#define SCANCODE_M 50 +#define SCANCODE_COMMA 51 +#define SCANCODE_PERIOD 52 +#define SCANCODE_SLASH 53 + +#define SCANCODE_RIGHTSHIFT 54 +#define SCANCODE_KEYPADMULTIPLY 55 + +#define SCANCODE_LEFTALT 56 +#define SCANCODE_SPACE 57 +#define SCANCODE_CAPSLOCK 58 + +#define SCANCODE_F1 59 +#define SCANCODE_F2 60 +#define SCANCODE_F3 61 +#define SCANCODE_F4 62 +#define SCANCODE_F5 63 +#define SCANCODE_F6 64 +#define SCANCODE_F7 65 +#define SCANCODE_F8 66 +#define SCANCODE_F9 67 +#define SCANCODE_F10 68 + +#define SCANCODE_NUMLOCK 69 +#define SCANCODE_SCROLLLOCK 70 + +#define SCANCODE_KEYPAD7 71 +#define SCANCODE_CURSORUPLEFT 71 +#define SCANCODE_KEYPAD8 72 +#define SCANCODE_CURSORUP 72 +#define SCANCODE_KEYPAD9 73 +#define SCANCODE_CURSORUPRIGHT 73 +#define SCANCODE_KEYPADMINUS 74 +#define SCANCODE_KEYPAD4 75 +#define SCANCODE_CURSORLEFT 75 +#define SCANCODE_KEYPAD5 76 +#define SCANCODE_KEYPAD6 77 +#define SCANCODE_CURSORRIGHT 77 +#define SCANCODE_KEYPADPLUS 78 +#define SCANCODE_KEYPAD1 79 +#define SCANCODE_CURSORDOWNLEFT 79 +#define SCANCODE_KEYPAD2 80 +#define SCANCODE_CURSORDOWN 80 +#define SCANCODE_KEYPAD3 81 +#define SCANCODE_CURSORDOWNRIGHT 81 +#define SCANCODE_KEYPAD0 82 +#define SCANCODE_KEYPADPERIOD 83 + +#define SCANCODE_LESS 86 + +#define SCANCODE_F11 87 +#define SCANCODE_F12 88 + +#define SCANCODE_KEYPADENTER 96 +#define SCANCODE_RIGHTCONTROL 97 +#define SCANCODE_CONTROL 97 +#define SCANCODE_KEYPADDIVIDE 98 +#define SCANCODE_PRINTSCREEN 99 +#define SCANCODE_RIGHTALT 100 +#define SCANCODE_BREAK 101 /* Beware: is 119 */ +#define SCANCODE_BREAK_ALTERNATIVE 119 /* on some keyboards! */ + +#define SCANCODE_HOME 102 +#define SCANCODE_CURSORBLOCKUP 103 /* Cursor key block */ +#define SCANCODE_PAGEUP 104 +#define SCANCODE_CURSORBLOCKLEFT 105 /* Cursor key block */ +#define SCANCODE_CURSORBLOCKRIGHT 106 /* Cursor key block */ +#define SCANCODE_END 107 +#define SCANCODE_CURSORBLOCKDOWN 108 /* Cursor key block */ +#define SCANCODE_PAGEDOWN 109 +#define SCANCODE_INSERT 110 +#define SCANCODE_REMOVE 111 + +#define SCANCODE_RIGHTWIN 126 +#define SCANCODE_LEFTWIN 125 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/SDL_gsmouse.c Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,146 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <sys/ioctl.h> + +#include "SDL_error.h" +#include "SDL_mouse.h" +#include "SDL_events_c.h" +#include "SDL_cursor_c.h" +#include "SDL_gsvideo.h" +#include "SDL_gsmouse_c.h" + + +/* The implementation dependent data for the window manager cursor */ +struct WMcursor { + int unused; +}; + +/* There isn't any implementation dependent data */ +void GS_FreeWMCursor(_THIS, WMcursor *cursor) +{ + return; +} + +/* There isn't any implementation dependent data */ +WMcursor *GS_CreateWMCursor(_THIS, + Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y) +{ + return((WMcursor *)0x01); +} + +static void GS_MoveCursor(_THIS, SDL_Cursor *cursor, int x, int y) +{ + SDL_Surface *screen; + struct ps2_image image; + SDL_Rect area; + int mouse_y1, mouse_y2; + void *saved_pixels; + int screen_updated; + + /* Lock so we don't interrupt an update with mouse motion */ + SDL_LockCursor(); + + /* Make sure any pending DMA has completed */ + if ( dma_pending ) { + ioctl(console_fd, PS2IOC_SENDQCT, 1); + dma_pending = 0; + } + + /* Remove the cursor image from the DMA area */ + screen = this->screen; + saved_pixels = screen->pixels; + screen->pixels = mapped_mem + screen->offset; + screen_updated = 0; + if ( cursor_drawn ) { + SDL_EraseCursorNoLock(this->screen); + cursor_drawn = 0; + screen_updated = 1; + } + + /* Save the current mouse area */ + SDL_MouseRect(&area); + mouse_y1 = area.y; + mouse_y2 = area.y+area.h; + + /* Only draw the new cursor if there was one passed in */ + if ( cursor ) { + /* Set the new location */ + cursor->area.x = (x - cursor->hot_x); + cursor->area.y = (y - cursor->hot_y); + + /* Draw the cursor at the new location */ + if ( (SDL_cursorstate & CURSOR_VISIBLE) && screen->pixels ) { + SDL_DrawCursorNoLock(screen); + cursor_drawn = 1; + screen_updated = 1; + } + } + screen->pixels = saved_pixels; + + /* Update the affected area of the screen */ + if ( screen_updated ) { + SDL_MouseRect(&area); + if ( area.y < mouse_y1 ) { + mouse_y1 = area.y; + } + if ( (area.y+area.h) > mouse_y2 ) { + mouse_y2 = area.y+area.h; + } + image = screen_image; + image.y = screen->offset / screen->pitch + mouse_y1; + image.h = mouse_y2 - mouse_y1; + image.ptr = mapped_mem + image.y * screen->pitch; + ioctl(console_fd, PS2IOC_LOADIMAGE, &image); + } + + /* We're finished */ + SDL_UnlockCursor(); +} + +void GS_MoveWMCursor(_THIS, int x, int y) +{ + GS_MoveCursor(this, SDL_cursor, x, y); +} + +int GS_ShowWMCursor(_THIS, WMcursor *wmcursor) +{ + SDL_Cursor *cursor; + int x, y; + + /* Draw the cursor at the appropriate location */ + SDL_GetMouseState(&x, &y); + if ( wmcursor ) { + cursor = SDL_cursor; + } else { + cursor = NULL; + } + GS_MoveCursor(this, cursor, x, y); + return(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/SDL_gsmouse_c.h Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,43 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +#include "SDL_gsvideo.h" + +/* This is the maximum size of the cursor sprite */ +#define CURSOR_W 32 +#define CURSOR_H 32 +#define CURSOR_W_POW 5 /* 32 = 2^5 */ +#define CURSOR_H_POW 5 /* 32 = 2^5 */ + +/* Functions to be exported */ +extern void GS_FreeWMCursor(_THIS, WMcursor *cursor); +extern WMcursor *GS_CreateWMCursor(_THIS, + Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y); +extern void GS_DrawCursor(SDL_Surface *screen); +extern void GS_EraseCursor(SDL_Surface *screen); +extern void GS_MoveWMCursor(_THIS, int x, int y); +extern int GS_ShowWMCursor(_THIS, WMcursor *cursor);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/SDL_gsvideo.c Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,577 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +/* Framebuffer console based SDL video driver implementation. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include "SDL.h" +#include "SDL_error.h" +#include "SDL_video.h" +#include "SDL_mouse.h" +#include "SDL_sysvideo.h" +#include "SDL_pixels_c.h" +#include "SDL_events_c.h" +#include "SDL_cursor_c.h" +#include "SDL_gsvideo.h" +#include "SDL_gsmouse_c.h" +#include "SDL_gsevents_c.h" +#include "SDL_gsyuv_c.h" + + +/* Initialization/Query functions */ +static int GS_VideoInit(_THIS, SDL_PixelFormat *vformat); +static SDL_Rect **GS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); +static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); +static int GS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors); +static void GS_VideoQuit(_THIS); + +/* Hardware surface functions */ +static int GS_AllocHWSurface(_THIS, SDL_Surface *surface); +static int GS_LockHWSurface(_THIS, SDL_Surface *surface); +static void GS_UnlockHWSurface(_THIS, SDL_Surface *surface); +static void GS_FreeHWSurface(_THIS, SDL_Surface *surface); + +/* GS driver bootstrap functions */ + +static int GS_Available(void) +{ + int console, memory; + + console = open(PS2_DEV_GS, O_RDWR, 0); + if ( console >= 0 ) { + close(console); + } + memory = open(PS2_DEV_MEM, O_RDWR, 0); + if ( memory >= 0 ) { + close(memory); + } + return((console >= 0) && (memory >= 0)); +} + +static void GS_DeleteDevice(SDL_VideoDevice *device) +{ + free(device->hidden); + free(device); +} + +static SDL_VideoDevice *GS_CreateDevice(int devindex) +{ + SDL_VideoDevice *this; + + /* Initialize all variables that we clean on shutdown */ + this = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice)); + if ( this ) { + memset(this, 0, (sizeof *this)); + this->hidden = (struct SDL_PrivateVideoData *) + malloc((sizeof *this->hidden)); + } + if ( (this == NULL) || (this->hidden == NULL) ) { + SDL_OutOfMemory(); + if ( this ) { + free(this); + } + return(0); + } + memset(this->hidden, 0, (sizeof *this->hidden)); + mouse_fd = -1; + keyboard_fd = -1; + + /* Set the function pointers */ + this->VideoInit = GS_VideoInit; + this->ListModes = GS_ListModes; + this->SetVideoMode = GS_SetVideoMode; + this->CreateYUVOverlay = GS_CreateYUVOverlay; + this->SetColors = GS_SetColors; + this->UpdateRects = NULL; + this->VideoQuit = GS_VideoQuit; + this->AllocHWSurface = GS_AllocHWSurface; + this->CheckHWBlit = NULL; + this->FillHWRect = NULL; + this->SetHWColorKey = NULL; + this->SetHWAlpha = NULL; + this->LockHWSurface = GS_LockHWSurface; + this->UnlockHWSurface = GS_UnlockHWSurface; + this->FlipHWSurface = NULL; + this->FreeHWSurface = GS_FreeHWSurface; + this->SetIcon = NULL; + this->SetCaption = NULL; + this->GetWMInfo = NULL; + this->FreeWMCursor = GS_FreeWMCursor; + this->CreateWMCursor = GS_CreateWMCursor; + this->ShowWMCursor = GS_ShowWMCursor; + this->MoveWMCursor = GS_MoveWMCursor; + this->InitOSKeymap = GS_InitOSKeymap; + this->PumpEvents = GS_PumpEvents; + + this->free = GS_DeleteDevice; + + return this; +} + +VideoBootStrap PS2GS_bootstrap = { + "ps2gs", "PlayStation 2 Graphics Synthesizer", + GS_Available, GS_CreateDevice +}; + +/* These are the pixel formats for the 32, 24, and 16 bit video modes */ +static struct { + int bpp; + Uint32 r; + Uint32 g; + Uint32 b; +} GS_pixelmasks[] = { + { 32, 0x000000FF, /* RGB little-endian */ + 0x0000FF00, + 0x00FF0000 }, + { 24, 0x000000FF, /* RGB little-endian */ + 0x0000FF00, + 0x00FF0000 }, + { 16, 0x0000001f, /* RGB little-endian */ + 0x000003e0, + 0x00007c00 }, +}; +/* This is a mapping from SDL bytes-per-pixel to GS pixel format */ +static int GS_formatmap[] = { + -1, /* 0 bpp, not a legal value */ + -1, /* 8 bpp, not supported (yet?) */ + PS2_GS_PSMCT16, /* 16 bpp */ + PS2_GS_PSMCT24, /* 24 bpp */ + PS2_GS_PSMCT32 /* 32 bpp */ +}; + +static unsigned long long head_tags[] __attribute__((aligned(16))) = { + 4 | (1LL << 60), /* GIFtag */ + 0x0e, /* A+D */ + 0, /* 2 */ + PS2_GS_BITBLTBUF, + 0, /* 4 */ + PS2_GS_TRXPOS, + 0, /* 6 */ + PS2_GS_TRXREG, + 0, /* 8 */ + PS2_GS_TRXDIR +}; + +#define MAXIMG (32767 * 16) +#define MAXTAGS 8 + +static inline int loadimage_nonblock(int fd, struct ps2_image *image, int size, + unsigned long long *hm, + unsigned long long *im) +{ + struct ps2_plist plist; + struct ps2_packet packet[1 + MAXTAGS * 2]; + int isize; + int pnum, it, eop; + char *data; + + /* initialize the variables */ + data = (char *)image->ptr; + pnum = it = eop = 0; + plist.packet = packet; + + /* make BITBLT packet */ + packet[pnum].ptr = hm; + packet[pnum].len = sizeof(head_tags); + pnum++; + hm[2] = ((unsigned long long)image->fbp << 32) | + ((unsigned long long)image->fbw << 48) | + ((unsigned long long)image->psm << 56); + hm[4] = ((unsigned long long)image->x << 32) | + ((unsigned long long)image->y << 48); + hm[6] = (unsigned long long)image->w | + ((unsigned long long)image->h << 32); + + /* make image mode tags */ + while (!eop) { + isize = size > MAXIMG ? MAXIMG : size; + size -= isize; + eop = (size == 0); + + packet[pnum].ptr = &im[it]; + packet[pnum].len = sizeof(unsigned long long) * 2; + pnum++; + im[it++] = (isize >> 4) | (eop ? (1 << 15) : 0) | (2LL << 58); + im[it++] = 0; + + packet[pnum].ptr = (void *)data; + packet[pnum].len = isize; + pnum++; + data += isize; + } + plist.num = pnum; + + return ioctl(fd, PS2IOC_SENDL, &plist); +} + +static int GS_VideoInit(_THIS, SDL_PixelFormat *vformat) +{ + struct ps2_screeninfo vinfo; + + /* Initialize the library */ + console_fd = open(PS2_DEV_GS, O_RDWR, 0); + if ( console_fd < 0 ) { + SDL_SetError("Unable to open %s", PS2_DEV_GS); + return(-1); + } + memory_fd = open(PS2_DEV_MEM, O_RDWR, 0); + if ( memory_fd < 0 ) { + close(console_fd); + console_fd = -1; + SDL_SetError("Unable to open %s", PS2_DEV_MEM); + return(-1); + } + + /* Determine the current screen depth */ + if ( ioctl(console_fd, PS2IOC_GSCREENINFO, &vinfo) < 0 ) { + close(memory_fd); + close(console_fd); + console_fd = -1; + SDL_SetError("Couldn't get console pixel format"); + return(-1); + } + if ( vinfo.mode != PS2_GS_VESA ) { + GS_VideoQuit(this); + SDL_SetError("Console must be in VESA video mode"); + return(-1); + } + switch (vinfo.psm) { + /* Supported pixel formats */ + case PS2_GS_PSMCT32: + case PS2_GS_PSMCT24: + case PS2_GS_PSMCT16: + break; + default: + GS_VideoQuit(this); + SDL_SetError("Unknown console pixel format: %d", vinfo.psm); + return(-1); + } + vformat->BitsPerPixel = GS_pixelmasks[vinfo.psm].bpp; + vformat->Rmask = GS_pixelmasks[vinfo.psm].r; + vformat->Gmask = GS_pixelmasks[vinfo.psm].g; + vformat->Bmask = GS_pixelmasks[vinfo.psm].b; + saved_vinfo = vinfo; + + /* Enable mouse and keyboard support */ + if ( GS_OpenKeyboard(this) < 0 ) { + GS_VideoQuit(this); + SDL_SetError("Unable to open keyboard"); + return(-1); + } + if ( GS_OpenMouse(this) < 0 ) { + const char *sdl_nomouse; + + sdl_nomouse = getenv("SDL_NOMOUSE"); + if ( ! sdl_nomouse ) { + GS_VideoQuit(this); + SDL_SetError("Unable to open mouse"); + return(-1); + } + } + + /* We're done! */ + return(0); +} + +static SDL_Rect **GS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) +{ + static SDL_Rect GS_mode_list[] = { + { 0, 0, 1280, 1024 }, + { 0, 0, 1024, 768 }, + { 0, 0, 800, 600 }, + { 0, 0, 640, 480 } + }; + static SDL_Rect *GS_modes[] = { + &GS_mode_list[0], + &GS_mode_list[1], + &GS_mode_list[2], + &GS_mode_list[3], + NULL + }; + SDL_Rect **modes; + + switch (format->BitsPerPixel) { + case 16: + case 24: + case 32: + modes = GS_modes; + break; + default: + modes = NULL; + break; + } + return(modes); +} + +/* Various screen update functions available */ +static void GS_DMAFullUpdate(_THIS, int numrects, SDL_Rect *rects); + +static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface *current, + int width, int height, int bpp, Uint32 flags) +{ + struct ps2_screeninfo vinfo; + + /* Set the terminal into graphics mode */ + if ( GS_EnterGraphicsMode(this) < 0 ) { + return(NULL); + } + + /* Set the video mode and get the final screen format */ + if ( ioctl(console_fd, PS2IOC_GSCREENINFO, &vinfo) < 0 ) { + SDL_SetError("Couldn't get console screen info"); + return(NULL); + } + if ( (vinfo.w != width) || (vinfo.h != height) || + (GS_pixelmasks[vinfo.psm].bpp != bpp) ) { + switch (width) { + case 640: + vinfo.res = PS2_GS_640x480; + break; + case 800: + vinfo.res = PS2_GS_800x600; + break; + case 1024: + vinfo.res = PS2_GS_1024x768; + break; + case 1280: + vinfo.res = PS2_GS_1280x1024; + break; + default: + SDL_SetError("Unsupported resolution: %dx%d\n", + width, height); + return(NULL); + } + vinfo.res |= (PS2_GS_75Hz << 8); + vinfo.w = width; + vinfo.h = height; + vinfo.fbp = 0; + vinfo.psm = GS_formatmap[bpp/8]; + if ( vinfo.psm < 0 ) { + SDL_SetError("Unsupported depth: %d bpp\n", bpp); + return(NULL); + } + if ( ioctl(console_fd, PS2IOC_SSCREENINFO, &vinfo) < 0 ) { + SDL_SetError("Couldn't set console screen info"); + return(NULL); + } + + /* Unmap the previous DMA buffer */ + if ( mapped_mem ) { + munmap(mapped_mem, mapped_len); + mapped_mem = NULL; + } + } + if ( ! SDL_ReallocFormat(current, GS_pixelmasks[vinfo.psm].bpp, + GS_pixelmasks[vinfo.psm].r, + GS_pixelmasks[vinfo.psm].g, + GS_pixelmasks[vinfo.psm].b, 0) ) { + return(NULL); + } + + /* Set up the new mode framebuffer */ + current->flags = SDL_FULLSCREEN; + current->w = vinfo.w; + current->h = vinfo.h; + current->pitch = SDL_CalculatePitch(current); + + /* Memory map the DMA area for block memory transfer */ + if ( ! mapped_mem ) { + pixels_len = height * current->pitch; + mapped_len = pixels_len + + /* Screen update DMA command area */ + sizeof(head_tags) + ((2 * MAXTAGS) * 16); + mapped_mem = mmap(0, mapped_len, PROT_READ|PROT_WRITE, + MAP_SHARED, memory_fd, 0); + if ( mapped_mem == MAP_FAILED ) { + SDL_SetError("Unable to map %d bytes for DMA", + mapped_len); + mapped_mem = NULL; + return(NULL); + } + + /* Set up the entire screen for DMA transfer */ + screen_image.ptr = mapped_mem; + screen_image.fbp = 0; + screen_image.fbw = (vinfo.w + 63) / 64; + screen_image.psm = vinfo.psm; + screen_image.x = 0; + screen_image.y = 0; + screen_image.w = vinfo.w; + screen_image.h = vinfo.h; + + /* get screen image data size (qword aligned) */ + screen_image_size = (vinfo.w * vinfo.h); + switch (screen_image.psm) { + case PS2_GS_PSMCT32: + screen_image_size *= 4; + break; + case PS2_GS_PSMCT24: + screen_image_size *= 3; + break; + case PS2_GS_PSMCT16: + screen_image_size *= 2; + break; + } + screen_image_size = (screen_image_size + 15) & ~15; + + /* Set up the memory for screen update DMA commands */ + head_tags_mem = (unsigned long long *) + (mapped_mem + pixels_len); + image_tags_mem = (unsigned long long *) + ((caddr_t)head_tags_mem + sizeof(head_tags)); + memcpy(head_tags_mem, head_tags, sizeof(head_tags)); + } + current->pixels = NULL; + if ( getenv("SDL_FULLSCREEN_UPDATE") ) { + /* Correct semantics */ + current->flags |= SDL_ASYNCBLIT; + } else { + /* We lie here - the screen memory isn't really the visible + display memory and still requires an update, but this + has the desired effect for most applications. + */ + current->flags |= SDL_HWSURFACE; + } + + /* Set the update rectangle function */ + this->UpdateRects = GS_DMAFullUpdate; + + /* We're done */ + return(current); +} + +/* We don't support hardware surfaces yet */ +static int GS_AllocHWSurface(_THIS, SDL_Surface *surface) +{ + return(-1); +} +static void GS_FreeHWSurface(_THIS, SDL_Surface *surface) +{ + return; +} +static int GS_LockHWSurface(_THIS, SDL_Surface *surface) +{ + if ( surface == this->screen ) { + /* Since mouse motion affects 'pixels', lock it */ + SDL_LockCursor(); + + /* Make sure any pending DMA has completed */ + if ( dma_pending ) { + ioctl(console_fd, PS2IOC_SENDQCT, 1); + dma_pending = 0; + } + + /* If the cursor is drawn on the DMA area, remove it */ + if ( cursor_drawn ) { + surface->pixels = mapped_mem + surface->offset; + SDL_EraseCursorNoLock(this->screen); + cursor_drawn = 0; + } + + /* Set the surface pixels to the base of the DMA area */ + surface->pixels = mapped_mem; + + /* We're finished! */ + SDL_UnlockCursor(); + } + return(0); +} +static void GS_UnlockHWSurface(_THIS, SDL_Surface *surface) +{ + if ( surface == this->screen ) { + /* Since mouse motion affects 'pixels', lock it */ + SDL_LockCursor(); + surface->pixels = NULL; + SDL_UnlockCursor(); + } +} + +static void GS_DMAFullUpdate(_THIS, int numrects, SDL_Rect *rects) +{ + /* Lock so we aren't interrupted by a mouse update */ + SDL_LockCursor(); + + /* Make sure any pending DMA has completed */ + if ( dma_pending ) { + ioctl(console_fd, PS2IOC_SENDQCT, 1); + dma_pending = 0; + } + + /* If the mouse is visible, draw it on the DMA area */ + if ( (SDL_cursorstate & CURSOR_VISIBLE) && !cursor_drawn ) { + this->screen->pixels = mapped_mem + this->screen->offset; + SDL_DrawCursorNoLock(this->screen); + this->screen->pixels = NULL; + cursor_drawn = 1; + } + + /* Put the image onto the screen */ + loadimage_nonblock(console_fd, + &screen_image, screen_image_size, + head_tags_mem, image_tags_mem); + dma_pending = 1; + + /* We're finished! */ + SDL_UnlockCursor(); +} + +static int GS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) +{ + return(0); +} + +static void GS_VideoQuit(_THIS) +{ + /* Close console and input file descriptors */ + if ( console_fd > 0 ) { + /* Unmap the video framebuffer */ + if ( mapped_mem ) { + /* Unmap the video framebuffer */ + munmap(mapped_mem, mapped_len); + mapped_mem = NULL; + } + close(memory_fd); + + /* Restore the original video mode */ + if ( GS_InGraphicsMode(this) ) { + ioctl(console_fd, PS2IOC_SSCREENINFO, &saved_vinfo); + } + + /* We're all done with the graphics device */ + close(console_fd); + console_fd = -1; + } + GS_CloseMouse(this); + GS_CloseKeyboard(this); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/SDL_gsvideo.h Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,92 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +#ifndef _SDL_gsvideo_h +#define _SDL_gsvideo_h + +#include <sys/types.h> +#include <termios.h> +#include <linux/ps2/dev.h> +#include <linux/ps2/gs.h> + +#include "SDL_mouse.h" +#include "SDL_mutex.h" +#include "SDL_sysvideo.h" + +/* Hidden "this" pointer for the video functions */ +#define _THIS SDL_VideoDevice *this + + +/* Private display data */ +struct SDL_PrivateVideoData { + /* Gotta love that simple PS2 graphics interface. :) */ + int console_fd; + int memory_fd; + struct ps2_screeninfo saved_vinfo; + + /* Ye olde linux keyboard code */ + int current_vt; + int saved_vt; + int keyboard_fd; + int saved_kbd_mode; + struct termios saved_kbd_termios; + + /* Ye olde linux mouse code */ + int mouse_fd; + int cursor_drawn; + + /* The memory mapped DMA area and associated variables */ + caddr_t mapped_mem; + int pixels_len; + int mapped_len; + struct ps2_image screen_image; + int screen_image_size; + unsigned long long *head_tags_mem; + unsigned long long *image_tags_mem; + int dma_pending; +}; +/* Old variable names */ +#define console_fd (this->hidden->console_fd) +#define memory_fd (this->hidden->memory_fd) +#define saved_vinfo (this->hidden->saved_vinfo) +#define current_vt (this->hidden->current_vt) +#define saved_vt (this->hidden->saved_vt) +#define keyboard_fd (this->hidden->keyboard_fd) +#define saved_kbd_mode (this->hidden->saved_kbd_mode) +#define saved_kbd_termios (this->hidden->saved_kbd_termios) +#define mouse_fd (this->hidden->mouse_fd) +#define cursor_drawn (this->hidden->cursor_drawn) +#define mapped_mem (this->hidden->mapped_mem) +#define pixels_len (this->hidden->pixels_len) +#define mapped_len (this->hidden->mapped_len) +#define screen_image (this->hidden->screen_image) +#define screen_image_size (this->hidden->screen_image_size) +#define head_tags_mem (this->hidden->head_tags_mem) +#define image_tags_mem (this->hidden->image_tags_mem) +#define dma_pending (this->hidden->dma_pending) + +#endif /* _SDL_gsvideo_h */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/SDL_gsyuv.c Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,467 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +/* This is the Playstation 2 implementation of YUV video overlays */ + +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <asm/page.h> /* For definition of PAGE_SIZE */ + +#include "SDL_error.h" +#include "SDL_video.h" +#include "SDL_gsyuv_c.h" +#include "SDL_yuvfuncs.h" + +/* The maximum number of 16x16 pixel block converted at once */ +#define MAX_MACROBLOCKS 1024 /* 2^10 macroblocks at once */ + +/* The functions used to manipulate video overlays */ +static struct private_yuvhwfuncs gs_yuvfuncs = { + GS_LockYUVOverlay, + GS_UnlockYUVOverlay, + GS_DisplayYUVOverlay, + GS_FreeYUVOverlay +}; + +struct private_yuvhwdata { + int ipu_fd; + Uint8 *pixels; + int macroblocks; + int dma_len; + caddr_t dma_mem; + caddr_t ipu_imem; + caddr_t ipu_omem; + caddr_t dma_tags; + unsigned long long *stretch_x1y1; + unsigned long long *stretch_x2y2; + struct ps2_plist plist; + + /* These are just so we don't have to allocate them separately */ + Uint16 pitches[3]; + Uint8 *planes[3]; +}; + +static int power_of_2(int value) +{ + int shift; + + for ( shift = 0; (1<<shift) < value; ++shift ) { + /* Keep looking */ ; + } + return(shift); +} + +SDL_Overlay *GS_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display) +{ + SDL_Overlay *overlay; + struct private_yuvhwdata *hwdata; + int map_offset; + unsigned long long *tags; + caddr_t base; + int bpp; + int fbp, fbw, psm; + int x, y, w, h; + int pnum; + struct ps2_packet *packet; + struct ps2_packet tex_packet; + + /* We can only decode blocks of 16x16 pixels */ + if ( (width & 15) || (height & 15) ) { + SDL_SetError("Overlay width/height must be multiples of 16"); + return(NULL); + } + /* Make sure the image isn't too large for a single DMA transfer */ + if ( ((width/16) * (height/16)) > MAX_MACROBLOCKS ) { + SDL_SetError("Overlay too large (maximum size: %d pixels)", + MAX_MACROBLOCKS * 16 * 16); + return(NULL); + } + + /* Double-check the requested format. For simplicity, we'll only + support planar YUV formats. + */ + switch (format) { + case SDL_YV12_OVERLAY: + case SDL_IYUV_OVERLAY: + /* Supported planar YUV format */ + break; + default: + SDL_SetError("Unsupported YUV format"); + return(NULL); + } + + /* Create the overlay structure */ + overlay = (SDL_Overlay *)malloc(sizeof *overlay); + if ( overlay == NULL ) { + SDL_OutOfMemory(); + return(NULL); + } + memset(overlay, 0, (sizeof *overlay)); + + /* Fill in the basic members */ + overlay->format = format; + overlay->w = width; + overlay->h = height; + + /* Set up the YUV surface function structure */ + overlay->hwfuncs = &gs_yuvfuncs; + overlay->hw_overlay = 1; + + /* Create the pixel data */ + hwdata = (struct private_yuvhwdata *)malloc(sizeof *hwdata); + overlay->hwdata = hwdata; + if ( hwdata == NULL ) { + SDL_FreeYUVOverlay(overlay); + SDL_OutOfMemory(); + return(NULL); + } + hwdata->ipu_fd = -1; + hwdata->pixels = (Uint8 *)malloc(width*height*2); + if ( hwdata->pixels == NULL ) { + SDL_FreeYUVOverlay(overlay); + SDL_OutOfMemory(); + return(NULL); + } + hwdata->macroblocks = (width/16) * (height/16); + + /* Find the pitch and offset values for the overlay */ + overlay->pitches = hwdata->pitches; + overlay->pixels = hwdata->planes; + switch (format) { + case SDL_YV12_OVERLAY: + case SDL_IYUV_OVERLAY: + overlay->pitches[0] = overlay->w; + overlay->pitches[1] = overlay->pitches[0] / 2; + overlay->pitches[2] = overlay->pitches[0] / 2; + overlay->pixels[0] = hwdata->pixels; + overlay->pixels[1] = overlay->pixels[0] + + overlay->pitches[0] * overlay->h; + overlay->pixels[2] = overlay->pixels[1] + + overlay->pitches[1] * overlay->h / 2; + overlay->planes = 3; + break; + default: + /* We should never get here (caught above) */ + break; + } + + /* Theoretically we could support several concurrent decode + streams queueing up on the same file descriptor, but for + simplicity we'll support only one. Opening the IPU more + than once will fail with EBUSY. + */ + hwdata->ipu_fd = open("/dev/ps2ipu", O_RDWR); + if ( hwdata->ipu_fd < 0 ) { + SDL_FreeYUVOverlay(overlay); + SDL_SetError("Playstation 2 IPU busy"); + return(NULL); + } + + /* Allocate a DMA area for pixel conversion */ + bpp = this->screen->format->BytesPerPixel; + map_offset = (mapped_len + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); + hwdata->dma_len = hwdata->macroblocks * (16 * 16 + 8 * 8 + 8 * 8) + + width * height * bpp + + hwdata->macroblocks * (16 * sizeof(long long)) + + 12 * sizeof(long long); + hwdata->dma_mem = mmap(0, hwdata->dma_len, PROT_READ|PROT_WRITE, + MAP_SHARED, memory_fd, map_offset); + if ( hwdata->dma_mem == MAP_FAILED ) { + hwdata->ipu_imem = (caddr_t)0; + SDL_FreeYUVOverlay(overlay); + SDL_SetError("Unable to map %d bytes for DMA", hwdata->dma_len); + return(NULL); + } + hwdata->ipu_imem = hwdata->dma_mem; + hwdata->ipu_omem = hwdata->ipu_imem + + hwdata->macroblocks * (16 * 16 + 8 * 8 + 8 * 8); + hwdata->dma_tags = hwdata->ipu_omem + width * height * bpp; + + /* Allocate memory for the DMA packets */ + hwdata->plist.num = hwdata->macroblocks * 4 + 1; + hwdata->plist.packet = (struct ps2_packet *)malloc( + hwdata->plist.num*sizeof(struct ps2_packet)); + if ( ! hwdata->plist.packet ) { + SDL_FreeYUVOverlay(overlay); + SDL_OutOfMemory(); + return(NULL); + } + pnum = 0; + packet = hwdata->plist.packet; + + /* Set up the tags to send the image to the screen */ + tags = (unsigned long long *)hwdata->dma_tags; + base = hwdata->ipu_omem; + fbp = screen_image.fbp; + fbw = screen_image.fbw; + psm = screen_image.psm; + y = screen_image.h; /* Offscreen video memory */ + for ( h=height/16; h; --h ) { + x = 0; /* Visible video memory */ + for ( w=width/16; w; --w ) { + /* The head tag */ + packet[pnum].ptr = &tags[0]; + packet[pnum].len = 10 * sizeof(*tags); + ++pnum; + tags[0] = 4 | (1LL << 60); /* GIFtag */ + tags[1] = 0x0e; /* A+D */ + tags[2] = ((unsigned long long)fbp << 32) | + ((unsigned long long)fbw << 48) | + ((unsigned long long)psm << 56); + tags[3] = PS2_GS_BITBLTBUF; + tags[4] = ((unsigned long long)x << 32) | + ((unsigned long long)y << 48); + tags[5] = PS2_GS_TRXPOS; + tags[6] = (unsigned long long)16 | + ((unsigned long long)16 << 32); + tags[7] = PS2_GS_TRXREG; + tags[8] = 0; + tags[9] = PS2_GS_TRXDIR; + /* Now the actual image data */ + packet[pnum].ptr = &tags[10]; + packet[pnum].len = 2 * sizeof(*tags); + ++pnum; + tags[10] = ((16*16*bpp) >> 4) | (2LL << 58); + tags[11] = 0; + packet[pnum].ptr = (void *)base; + packet[pnum].len = 16 * 16 * bpp; + ++pnum; + packet[pnum].ptr = &tags[12]; + packet[pnum].len = 2 * sizeof(*tags); + ++pnum; + tags[12] = (0 >> 4) | (1 << 15) | (2LL << 58); + tags[13] = 0; + + tags += 16; + base += 16 * 16 * bpp; + + x += 16; + } + y += 16; + } + + /* Set up the texture memory area for the video */ + tex_packet.ptr = tags; + tex_packet.len = 8 * sizeof(*tags); + tags[0] = 3 | (1LL << 60); /* GIFtag */ + tags[1] = 0x0e; /* A+D */ + tags[2] = (screen_image.h * screen_image.w) / 64 + + ((unsigned long long)fbw << 14) + + ((unsigned long long)psm << 20) + + ((unsigned long long)power_of_2(width) << 26) + + ((unsigned long long)power_of_2(height) << 30) + + ((unsigned long long)1 << 34) + + ((unsigned long long)1 << 35); + tags[3] = PS2_GS_TEX0_1; + tags[4] = (1 << 5) + (1 << 6); + tags[5] = PS2_GS_TEX1_1; + tags[6] = 0; + tags[7] = PS2_GS_TEXFLUSH; + ioctl(console_fd, PS2IOC_SEND, &tex_packet); + + /* Set up the tags for scaling the image */ + packet[pnum].ptr = tags; + packet[pnum].len = 12 * sizeof(*tags); + ++pnum; + tags[0] = 5 | (1LL << 60); /* GIFtag */ + tags[1] = 0x0e; /* A+D */ + tags[2] = 6 + (1 << 4) + (1 << 8); + tags[3] = PS2_GS_PRIM; + tags[4] = ((unsigned long long)0 * 16) + + (((unsigned long long)0 * 16) << 16); + tags[5] = PS2_GS_UV; + tags[6] = 0; /* X1, Y1 */ + tags[7] = PS2_GS_XYZ2; + hwdata->stretch_x1y1 = &tags[6]; + tags[8] = ((unsigned long long)overlay->w * 16) + + (((unsigned long long)overlay->h * 16) << 16); + tags[9] = PS2_GS_UV; + tags[10] = 0; /* X2, Y2 */ + tags[11] = PS2_GS_XYZ2; + hwdata->stretch_x2y2 = &tags[10]; + + /* We're all done.. */ + return(overlay); +} + +int GS_LockYUVOverlay(_THIS, SDL_Overlay *overlay) +{ + return(0); +} + +void GS_UnlockYUVOverlay(_THIS, SDL_Overlay *overlay) +{ + return; +} + +int GS_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *dstrect) +{ + struct private_yuvhwdata *hwdata; + __u32 cmd; + struct ps2_packet packet; + int h, w, i; + Uint32 *lum, *Cr, *Cb; + int lum_pitch; + int crb_pitch; + Uint32 *lum_src, *Cr_src, *Cb_src; + Uint32 *src, *dst; + unsigned int x, y; + SDL_Surface *screen; + + /* Find out where the various portions of the image are */ + hwdata = overlay->hwdata; + switch (overlay->format) { + case SDL_YV12_OVERLAY: + lum = (Uint32 *)overlay->pixels[0]; + Cr = (Uint32 *)overlay->pixels[1]; + Cb = (Uint32 *)overlay->pixels[2]; + break; + case SDL_IYUV_OVERLAY: + lum = (Uint32 *)overlay->pixels[0]; + Cr = (Uint32 *)overlay->pixels[2]; + Cb = (Uint32 *)overlay->pixels[1]; + default: + SDL_SetError("Unsupported YUV format in blit (??)"); + return(-1); + } + dst = (Uint32 *)hwdata->ipu_imem; + lum_pitch = overlay->w/4; + crb_pitch = (overlay->w/2)/4; + + /* Copy blocks of 16x16 pixels to the DMA area */ + for ( h=overlay->h/16; h; --h ) { + lum_src = lum; + Cr_src = Cr; + Cb_src = Cb; + for ( w=overlay->w/16; w; --w ) { + src = lum_src; + for ( i=0; i<16; ++i ) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + src += lum_pitch; + dst += 4; + } + src = Cb_src; + for ( i=0; i<8; ++i ) { + dst[0] = src[0]; + dst[1] = src[1]; + src += crb_pitch; + dst += 2; + } + src = Cr_src; + for ( i=0; i<8; ++i ) { + dst[0] = src[0]; + dst[1] = src[1]; + src += crb_pitch; + dst += 2; + } + lum_src += 16 / 4; + Cb_src += 8 / 4; + Cr_src += 8 / 4; + } + lum += lum_pitch * 16; + Cr += crb_pitch * 8; + Cb += crb_pitch * 8; + } + + /* Send the macroblock data to the IPU */ +#ifdef DEBUG_YUV + fprintf(stderr, "Sending data to IPU..\n"); +#endif + packet.ptr = hwdata->ipu_imem; + packet.len = hwdata->macroblocks * (16 * 16 + 8 * 8 + 8 * 8); + ioctl(hwdata->ipu_fd, PS2IOC_SENDA, &packet); + + /* Trigger the DMA to the IPU for conversion */ +#ifdef DEBUG_YUV + fprintf(stderr, "Trigging conversion command\n"); +#endif + cmd = (7 << 28) + hwdata->macroblocks; + if ( screen_image.psm == PS2_GS_PSMCT16 ) { + cmd += (1 << 27) + /* Output RGB 555 */ + (1 << 26); /* Dither output */ + } + ioctl(hwdata->ipu_fd, PS2IOC_SIPUCMD, &cmd); + + /* Retrieve the converted image from the IPU */ +#ifdef DEBUG_YUV + fprintf(stderr, "Retrieving data from IPU..\n"); +#endif + packet.ptr = hwdata->ipu_omem; + packet.len = overlay->w * overlay->h * + this->screen->format->BytesPerPixel; + ioctl(hwdata->ipu_fd, PS2IOC_RECV, &packet); + +#ifdef DEBUG_YUV + fprintf(stderr, "Copying image to screen..\n"); +#endif + /* Wait for previous DMA to complete */ + ioctl(console_fd, PS2IOC_SENDQCT, 1); + + /* Send the current image to the screen and scale it */ + screen = this->screen; + x = (unsigned int)dstrect->x; + y = (unsigned int)dstrect->y; + if ( screen->offset ) { + x += (screen->offset % screen->pitch) / + screen->format->BytesPerPixel; + y += (screen->offset / screen->pitch); + } + *hwdata->stretch_x1y1 = (x * 16) + ((y * 16) << 16); + x += (unsigned int)dstrect->w; + y += (unsigned int)dstrect->h; + *hwdata->stretch_x2y2 = (x * 16) + ((y * 16) << 16); + return ioctl(console_fd, PS2IOC_SENDL, &hwdata->plist); +} + +void GS_FreeYUVOverlay(_THIS, SDL_Overlay *overlay) +{ + struct private_yuvhwdata *hwdata; + + hwdata = overlay->hwdata; + if ( hwdata ) { + if ( hwdata->ipu_fd >= 0 ) { + close(hwdata->ipu_fd); + } + if ( hwdata->dma_mem ) { + munmap(hwdata->dma_mem, hwdata->dma_len); + } + if ( hwdata->plist.packet ) { + free(hwdata->plist.packet); + } + if ( hwdata->pixels ) { + free(hwdata->pixels); + } + free(hwdata); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/ps2gs/SDL_gsyuv_c.h Sat Jun 16 03:17:45 2001 +0000 @@ -0,0 +1,41 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +/* This is the Playstation 2 implementation of YUV video overlays */ + +#include "SDL_video.h" +#include "SDL_gsvideo.h" + +extern SDL_Overlay *GS_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display); + +extern int GS_LockYUVOverlay(_THIS, SDL_Overlay *overlay); + +extern void GS_UnlockYUVOverlay(_THIS, SDL_Overlay *overlay); + +extern int GS_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *dstrect); + +extern void GS_FreeYUVOverlay(_THIS, SDL_Overlay *overlay);