From: Staffan Ulfberg <staffan@ulfberg.se>
Date: 19 Nov 2005 01:00:48 +0100
Subject: [SDL] New driver for OpenBSD/wscons

Hello,

I've written an SDL driver for OpenBSD/wscons (console mode, somewhat
resembling the functionality of the svga driver for Linux).  I use it
for playing MAME on my Sharp Zaurus.  The alternative is to play under
X, which is slower.

I asked how to submit the driver a few days ago, and posted a link to
the patch in a follow-up, so maybe it was missed?

Anyway, the patch is on the web at:

http://multivac.fatburen.org/SDL-wscons.patch

Comments?

Staffan
import/tags/release-1.2.10
Ryan C. Gordon 2005-11-22 15:19:50 +00:00
parent bff0b45b0e
commit df2b13dc06
12 changed files with 1200 additions and 1 deletions

107
README.wscons Normal file
View File

@ -0,0 +1,107 @@
==============================================================================
Using the Simple DirectMedia Layer with OpenBSD/wscons
==============================================================================
The wscons SDL driver can be used to run SDL programs on OpenBSD
without running X. So far, the driver only runs on the Sharp Zaurus,
but the driver is written to be easily extended for other machines.
The main missing pieces are blitting routines for anything but 16 bit
displays, and keycode maps for other keyboards. Also, there is no
support for hardware palettes.
There is currently no mouse support.
To compile SDL with support for wscons, use the
"--enable-video-wscons" option when running configure. I used the
following command line:
./configure --disable-oss --disable-ltdl --enable-pthread-sem \
--disable-esd --disable-arts --disable-video-aalib \
--enable-openbsdaudio --enable-video-wscons \
--prefix=/usr/local --sysconfdir=/etc
Setting the console device to use
=================================
When starting an SDL program on a wscons console, the driver uses the
current virtual terminal (usually /dev/ttyC0). To force the driver to
use a specific terminal device, set the environment variable
SDL_WSCONSDEV:
bash$ SDL_WSCONSDEV=/dev/ttyC1 ./some-sdl-program
This is especially useful when starting an SDL program from a remote
login prompt (which is great for development). If you do this, and
want to use keyboard input, you should avoid having some other program
reading from the used virtual console (i.e., do not have a getty
running).
Rotating the display
====================
The display can be rotated by the wscons SDL driver. This is useful
for the Sharp Zaurus, since the display hardware is wired so that it
is correctly rotated only when the display is folded into "PDA mode."
When using the Zaurus in "normal," or "keyboard" mode, the hardware
screen is rotated 90 degrees anti-clockwise.
To let the wscons SDL driver rotate the screen, set the environment
variable SDL_VIDEO_WSCONS_ROTATION to "CW", "CCW", or "UD", for
clockwise, counter clockwise, and upside-down rotation respectively.
"CW" makes the screen appear correct on a Sharp Zaurus SL-C3100.
When using rotation in the driver, a "shadow" frame buffer is used to
hold the intermediary display, before blitting it to the actual
hardware frame buffer. This slows down performance a bit.
For completeness, the rotation "NONE" can be specified to use a shadow
frame buffer without actually rotating. Unsetting
SDL_VIDEO_WSCONS_ROTATION, or setting it to '' turns off the shadow
frame buffer for maximum performance.
Running MAME
============
Since my main motivation for writing the driver was playing MAME on
the Zaurus, I'll give a few hints:
XMame compiles just fine under OpenBSD.
I'm not sure this is strictly necessary, but set
MY_CPU = arm
in makefile.unix, and
CFLAGS.arm = -DLSB_FIRST -DALIGN_INTS -DALIGN_SHORTS
in src/unix/unix.max
to be sure.
The latest XMame (0.101 at this writing) is a very large program.
Either tinker with the make files to compile a version without support
for all drivers, or, get an older version of XMame. My recommendation
would be 0.37b16.
When running MAME, DO NOT SET SDL_VIDEO_WSCONS_ROTATION! Performace
is MUCH better without this, and it is COMPLETELY UNNECESSARY, since
MAME can rotate the picture itself while drawing, and does so MUCH
FASTER.
Use the Xmame command line option "-ror" to rotate the picture to the
right.
Acknowledgments
===============
I studied the wsfb driver for XFree86/Xorg quite a bit before writing
this, so there ought to be some similarities.
--
Staffan Ulfberg <staffan@ulfberg.se>

View File

@ -1645,6 +1645,37 @@ CheckQtopia()
fi
}
dnl Set up the wscons video driver if enabled
CheckWscons()
{
AC_ARG_ENABLE(video-wscons,
[ --enable-video-wscons use wscons video driver [default=no]],
, enable_video_wscons=no)
if test x$enable_video = xyes -a x$enable_video_wscons = xyes; then
AC_MSG_CHECKING(for wscons support)
video_wscons=no
AC_LANG_C
AC_TRY_COMPILE([
#include <sys/time.h>
#include <dev/wscons/wsconsio.h>
],[
],[
video_wscons=yes
])
AC_MSG_RESULT($video_wscons)
if test x$video_wscons = xyes; then
CFLAGS="$CFLAGS -DENABLE_WSCONS"
VIDEO_SUBDIRS="$VIDEO_SUBDIRS wscons"
VIDEO_DRIVERS="$VIDEO_DRIVERS wscons/libvideo_wscons.la"
else
AC_MSG_ERROR([
*** Failed to find wscons includes.])
fi
AC_LANG_C
fi
}
dnl Set up the PicoGUI video driver if enabled
CheckPicoGUI()
{
@ -2210,6 +2241,7 @@ case "$target" in
CheckNAS
CheckX11
CheckAAlib
CheckWscons
CheckOpenGL
CheckPTHREAD
CheckSIGACTION
@ -3088,6 +3120,7 @@ src/video/photon/Makefile
src/video/picogui/Makefile
src/video/ps2gs/Makefile
src/video/qtopia/Makefile
src/video/wscons/Makefile
src/video/quartz/Makefile
src/video/riscos/Makefile
src/video/svga/Makefile

View File

@ -9,7 +9,7 @@ DIST_SUBDIRS = dummy x11 dga nanox fbcon directfb vgl svga ggi aalib \
wincommon windib windx5 \
maccommon macdsp macrom riscos quartz \
bwindow ps2gs photon cybergfx epoc picogui \
ataricommon xbios gem dc qtopia XFree86
ataricommon xbios gem dc qtopia XFree86 wscons
DRIVERS = @VIDEO_DRIVERS@

View File

@ -411,6 +411,9 @@ extern VideoBootStrap GEM_bootstrap;
#ifdef ENABLE_QTOPIA
extern VideoBootStrap Qtopia_bootstrap;
#endif
#ifdef ENABLE_WSCONS
extern VideoBootStrap WSCONS_bootstrap;
#endif
#ifdef ENABLE_PICOGUI
extern VideoBootStrap PG_bootstrap;
#endif

View File

@ -63,6 +63,9 @@ static VideoBootStrap *bootstrap[] = {
#ifdef ENABLE_QTOPIA
&Qtopia_bootstrap,
#endif
#ifdef ENABLE_WSCONS
&WSCONS_bootstrap,
#endif
#ifdef ENABLE_FBCON
&FBCON_bootstrap,
#endif

View File

@ -0,0 +1,14 @@
## Makefile.am for SDL using the wscons video driver
noinst_LTLIBRARIES = libvideo_wscons.la
libvideo_wscons_la_SOURCES = $(WSCONS_SRCS)
# The SDL wscons video driver sources
WSCONS_SRCS = \
SDL_wsconsvideo.h \
SDL_wsconsevents.c \
SDL_wsconsevents_c.h \
SDL_wsconsmouse.c \
SDL_wsconsmouse_c.h \
SDL_wsconsvideo.c

View File

@ -0,0 +1,236 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 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@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
#include <sys/types.h>
#include <dev/wscons/wsdisplay_usl_io.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
#include "SDL.h"
#include "SDL_sysevents.h"
#include "SDL_events_c.h"
#include "SDL_wsconsvideo.h"
#include "SDL_wsconsevents_c.h"
static int posted = 0;
int WSCONS_InitKeyboard(_THIS)
{
struct termios tty;
if (ioctl(private->fd, WSKBDIO_GTYPE, &private->kbdType) == -1) {
WSCONS_ReportError("cannot get keyboard type: %s", strerror(errno));
return -1;
}
if (tcgetattr(private->fd, &private->saved_tty) == -1) {
WSCONS_ReportError("cannot get terminal attributes: %s", strerror(errno));
return -1;
}
private->did_save_tty = 1;
tty = private->saved_tty;
tty.c_iflag = IGNPAR | IGNBRK;
tty.c_oflag = 0;
tty.c_cflag = CREAD | CS8;
tty.c_lflag = 0;
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 1;
cfsetispeed(&tty, 9600);
cfsetospeed(&tty, 9600);
if (tcsetattr(private->fd, TCSANOW, &tty) < 0) {
WSCONS_ReportError("cannot set terminal attributes: %s", strerror(errno));
return -1;
}
if (ioctl(private->fd, KDSKBMODE, K_RAW) == -1) {
WSCONS_ReportError("cannot set raw keyboard mode: %s", strerror(errno));
return -1;
}
return 0;
}
void WSCONS_ReleaseKeyboard(_THIS)
{
if (private->fd != -1) {
if (ioctl(private->fd, KDSKBMODE, K_XLATE) == -1) {
WSCONS_ReportError("cannot restore keyboard to translated mode: %s",
strerror(errno));
}
if (private->did_save_tty) {
if (tcsetattr(private->fd, TCSANOW, &private->saved_tty) < 0) {
WSCONS_ReportError("cannot restore keynoard attributes: %s",
strerror(errno));
}
}
}
}
static void updateMouse()
{
}
static SDLKey keymap[128];
static SDL_keysym *TranslateKey(int scancode, SDL_keysym *keysym)
{
keysym->scancode = scancode;
keysym->sym = SDLK_UNKNOWN;
keysym->mod = KMOD_NONE;
if (scancode < SDL_TABLESIZE(keymap))
keysym->sym = keymap[scancode];
if (keysym->sym == SDLK_UNKNOWN)
printf("Unknown mapping for scancode %d\n", scancode);
return keysym;
}
static void updateKeyboard(_THIS)
{
unsigned char buf[100];
SDL_keysym keysym;
int n, i;
if ((n = read(private->fd, buf, sizeof(buf))) > 0) {
for (i = 0; i < n; i++) {
char c = buf[i] & 0x7f;
if (c == 224) // special key prefix -- what should we do with it?
continue;
int release = (buf[i] & 0x80) != 0;
posted += SDL_PrivateKeyboard(release ? SDL_RELEASED : SDL_PRESSED,
TranslateKey(c, &keysym));
}
}
}
void WSCONS_PumpEvents(_THIS)
{
do {
posted = 0;
updateMouse();
updateKeyboard(this);
} while (posted);
}
void WSCONS_InitOSKeymap(_THIS)
{
int i;
/* Make sure unknown keys are mapped correctly */
for (i=0; i < SDL_TABLESIZE(keymap); i++) {
keymap[i] = SDLK_UNKNOWN;
}
switch (private->kbdType) {
case WSKBD_TYPE_ZAURUS:
/* top row */
keymap[2] = SDLK_1;
keymap[3] = SDLK_2;
keymap[4] = SDLK_3;
keymap[5] = SDLK_4;
keymap[6] = SDLK_5;
keymap[7] = SDLK_6;
keymap[8] = SDLK_7;
keymap[9] = SDLK_8;
keymap[10] = SDLK_9;
keymap[11] = SDLK_0;
keymap[14] = SDLK_BACKSPACE;
/* second row */
keymap[16] = SDLK_q;
keymap[17] = SDLK_w;
keymap[18] = SDLK_e;
keymap[19] = SDLK_r;
keymap[20] = SDLK_t;
keymap[21] = SDLK_y;
keymap[22] = SDLK_u;
keymap[23] = SDLK_i;
keymap[24] = SDLK_o;
keymap[25] = SDLK_p;
/* third row */
keymap[15] = SDLK_TAB;
keymap[30] = SDLK_a;
keymap[31] = SDLK_s;
keymap[32] = SDLK_d;
keymap[33] = SDLK_f;
keymap[34] = SDLK_g;
keymap[35] = SDLK_h;
keymap[36] = SDLK_j;
keymap[37] = SDLK_k;
keymap[38] = SDLK_l;
/* fourth row */
keymap[42] = SDLK_LSHIFT;
keymap[44] = SDLK_z;
keymap[45] = SDLK_x;
keymap[46] = SDLK_c;
keymap[47] = SDLK_v;
keymap[48] = SDLK_b;
keymap[49] = SDLK_n;
keymap[50] = SDLK_m;
keymap[54] = SDLK_RSHIFT;
keymap[28] = SDLK_RETURN;
/* fifth row */
keymap[56] = SDLK_LALT;
keymap[29] = SDLK_LCTRL;
/* keymap[56] = ; */
keymap[0] = SDLK_LSUPER;
keymap[12] = SDLK_MINUS;
keymap[57] = SDLK_SPACE;
keymap[51] = SDLK_COMMA;
keymap[52] = SDLK_PERIOD;
/* misc */
keymap[59] = SDLK_F1;
keymap[60] = SDLK_F2;
keymap[61] = SDLK_F3;
keymap[62] = SDLK_F4;
keymap[63] = SDLK_F5;
keymap[1] = SDLK_ESCAPE;
/* keymap[28] = SDLK_KP_ENTER; */
keymap[72] = SDLK_UP;
keymap[75] = SDLK_LEFT;
keymap[77] = SDLK_RIGHT;
keymap[80] = SDLK_DOWN;
break;
default:
WSCONS_ReportError("Unable to map keys for keyboard type %u",
private->kbdType);
break;
}
}
/* end of SDL_wsconsevents.c ... */

View File

@ -0,0 +1,40 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 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@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
#include "SDL_wsconsvideo.h"
int WSCONS_InitKeyboard(_THIS);
void WSCONS_ReleaseKeyboard(_THIS);
/* Variables and functions exported by SDL_sysevents.c to other parts
of the native video subsystem (SDL_sysvideo.c)
*/
extern void WSCONS_InitOSKeymap(_THIS);
extern void WSCONS_PumpEvents(_THIS);
/* end of SDL_wsconsevents_c.h ... */

View File

@ -0,0 +1,40 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 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@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
#include <stdio.h>
#include "SDL_error.h"
#include "SDL_mouse.h"
#include "SDL_events_c.h"
#include "SDL_wsconsmouse_c.h"
/* The implementation dependent data for the window manager cursor */
struct WMcursor {
int unused;
};

View File

@ -0,0 +1,30 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 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@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
#include "SDL_wsconsvideo.h"
/* Functions to be exported */

View File

@ -0,0 +1,614 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 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@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <dev/wscons/wsdisplay_usl_io.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.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_wsconsvideo.h"
#include "SDL_wsconsevents_c.h"
#include "SDL_wsconsmouse_c.h"
#define WSCONSVID_DRIVER_NAME "wscons"
enum {
WSCONS_ROTATE_NONE = 0,
WSCONS_ROTATE_CCW = 90,
WSCONS_ROTATE_UD = 180,
WSCONS_ROTATE_CW = 270
};
#define min(a,b) ((a)<(b)?(a):(b))
/* Initialization/Query functions */
static int WSCONS_VideoInit(_THIS, SDL_PixelFormat *vformat);
static SDL_Rect **WSCONS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
static SDL_Surface *WSCONS_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
static int WSCONS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
static void WSCONS_VideoQuit(_THIS);
/* Hardware surface functions */
static int WSCONS_AllocHWSurface(_THIS, SDL_Surface *surface);
static int WSCONS_LockHWSurface(_THIS, SDL_Surface *surface);
static void WSCONS_UnlockHWSurface(_THIS, SDL_Surface *surface);
static void WSCONS_FreeHWSurface(_THIS, SDL_Surface *surface);
/* etc. */
static WSCONS_bitBlit WSCONS_blit16;
static WSCONS_bitBlit WSCONS_blit16blocked;
static void WSCONS_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
void WSCONS_ReportError(char *fmt, ...)
{
char message[200];
message[199] = '\0';
va_list vaArgs;
va_start(vaArgs, fmt);
vsnprintf(message, 199, fmt, vaArgs);
va_end(vaArgs);
SDL_SetError(message);
fprintf(stderr, "WSCONS error: %s\n", message);
}
/* WSCONS driver bootstrap functions */
static int WSCONS_Available(void)
{
return 1;
}
static void WSCONS_DeleteDevice(SDL_VideoDevice *device)
{
free(device->hidden);
free(device);
}
static SDL_VideoDevice *WSCONS_CreateDevice(int devindex)
{
SDL_VideoDevice *device;
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
if (device == NULL) {
SDL_OutOfMemory();
return 0;
}
memset(device, 0, (sizeof *device));
device->hidden =
(struct SDL_PrivateVideoData *)malloc((sizeof *device->hidden));
if (device->hidden == NULL) {
SDL_OutOfMemory();
free(device);
return(0);
}
memset(device->hidden, 0, (sizeof *device->hidden));
device->hidden->fd = -1;
/* Set the function pointers */
device->VideoInit = WSCONS_VideoInit;
device->ListModes = WSCONS_ListModes;
device->SetVideoMode = WSCONS_SetVideoMode;
device->SetColors = WSCONS_SetColors;
device->UpdateRects = WSCONS_UpdateRects;
device->VideoQuit = WSCONS_VideoQuit;
device->AllocHWSurface = WSCONS_AllocHWSurface;
device->LockHWSurface = WSCONS_LockHWSurface;
device->UnlockHWSurface = WSCONS_UnlockHWSurface;
device->FreeHWSurface = WSCONS_FreeHWSurface;
device->InitOSKeymap = WSCONS_InitOSKeymap;
device->PumpEvents = WSCONS_PumpEvents;
device->free = WSCONS_DeleteDevice;
return device;
}
VideoBootStrap WSCONS_bootstrap = {
WSCONSVID_DRIVER_NAME,
"SDL wscons video driver",
WSCONS_Available,
WSCONS_CreateDevice
};
#define WSCONSDEV_FORMAT "/dev/ttyC%01x"
int WSCONS_VideoInit(_THIS, SDL_PixelFormat *vformat)
{
char devnamebuf[30];
char *devname;
char *rotation;
int wstype;
int wsmode = WSDISPLAYIO_MODE_DUMBFB;
size_t len, mapsize;
int pagemask;
int width, height;
devname = getenv("SDL_WSCONSDEV");
if (devname == NULL) {
int activeVT;
if (ioctl(STDIN_FILENO, VT_GETACTIVE, &activeVT) == -1) {
WSCONS_ReportError("Unable to determine active terminal: %s",
strerror(errno));
return -1;
}
snprintf(devnamebuf, sizeof(devnamebuf), WSCONSDEV_FORMAT, activeVT - 1);
devname = devnamebuf;
}
private->fd = open(devname, O_RDWR | O_NONBLOCK, 0);
if (private->fd == -1) {
WSCONS_ReportError("open %s: %s", devname, strerror(errno));
return -1;
}
if (ioctl(private->fd, WSDISPLAYIO_GINFO, &private->info) == -1) {
WSCONS_ReportError("ioctl WSDISPLAY_GINFO: %s", strerror(errno));
return -1;
}
if (ioctl(private->fd, WSDISPLAYIO_GTYPE, &wstype) == -1) {
WSCONS_ReportError("ioctl WSDISPLAY_GTYPE: %s", strerror(errno));
return -1;
}
if (ioctl(private->fd, WSDISPLAYIO_LINEBYTES, &private->physlinebytes) == -1) {
WSCONS_ReportError("ioctl WSDISPLAYIO_LINEBYTES: %s", strerror(errno));
return -1;
}
if (private->info.depth > 8) {
if (wstype == WSDISPLAY_TYPE_SUN24 ||
wstype == WSDISPLAY_TYPE_SUNCG12 ||
wstype == WSDISPLAY_TYPE_SUNCG14 ||
wstype == WSDISPLAY_TYPE_SUNTCX ||
wstype == WSDISPLAY_TYPE_SUNFFB) {
private->redMask = 0x0000ff;
private->greenMask = 0x00ff00;
private->blueMask = 0xff0000;
} else if (wstype == WSDISPLAY_TYPE_PXALCD) {
private->redMask = 0x1f << 11;
private->greenMask = 0x3f << 5;
private->blueMask = 0x1f;
} else {
WSCONS_ReportError("Unknown video hardware");
return -1;
}
} else {
WSCONS_ReportError("Displays with 8 bpp or less are not supported");
return -1;
}
private->rotate = WSCONS_ROTATE_NONE;
rotation = getenv("SDL_VIDEO_WSCONS_ROTATION");
if (rotation != NULL) {
if (strlen(rotation) == 0) {
private->shadowFB = 0;
private->rotate = WSCONS_ROTATE_NONE;
printf("Not rotating, no shadow\n");
} else if (!strcmp(rotation, "NONE")) {
private->shadowFB = 1;
private->rotate = WSCONS_ROTATE_NONE;
printf("Not rotating, but still using shadow\n");
} else if (!strcmp(rotation, "CW")) {
private->shadowFB = 1;
private->rotate = WSCONS_ROTATE_CW;
printf("Rotating screen clockwise\n");
} else if (!strcmp(rotation, "CCW")) {
private->shadowFB = 1;
private->rotate = WSCONS_ROTATE_CCW;
printf("Rotating screen counter clockwise\n");
} else if (!strcmp(rotation, "UD")) {
private->shadowFB = 1;
private->rotate = WSCONS_ROTATE_UD;
printf("Rotating screen upside down\n");
} else {
WSCONS_ReportError("\"%s\" is not a valid value for "
"SDL_VIDEO_WSCONS_ROTATION", rotation);
return -1;
}
}
switch (private->info.depth) {
case 1:
case 4:
case 8:
len = private->physlinebytes * private->info.height;
break;
case 16:
if (private->physlinebytes == private->info.width) {
len = private->info.width * private->info.height * sizeof(short);
} else {
len = private->physlinebytes * private->info.height;
}
if (private->rotate == WSCONS_ROTATE_NONE ||
private->rotate == WSCONS_ROTATE_UD) {
private->blitFunc = WSCONS_blit16;
} else {
private->blitFunc = WSCONS_blit16blocked;
}
break;
case 32:
if (private->physlinebytes == private->info.width) {
len = private->info.width * private->info.height * sizeof(int);
} else {
len = private->physlinebytes * private->info.height;
}
break;
default:
WSCONS_ReportError("unsupported depth %d", private->info.depth);
return -1;
}
if (private->shadowFB && private->blitFunc == NULL) {
WSCONS_ReportError("Using software buffer, but no blitter function is "
"available for this %d bpp.", private->info.depth);
return -1;
}
if (ioctl(private->fd, WSDISPLAYIO_SMODE, &wsmode) == -1) {
WSCONS_ReportError("ioctl SMODE");
return -1;
}
pagemask = getpagesize() - 1;
mapsize = ((int)len + pagemask) & ~pagemask;
private->physmem = (Uint8 *)mmap(NULL, mapsize,
PROT_READ | PROT_WRITE, MAP_SHARED,
private->fd, (off_t)0);
if (private->physmem == (Uint8 *)MAP_FAILED) {
private->physmem = NULL;
WSCONS_ReportError("mmap: %s", strerror(errno));
return -1;
}
private->fbmem_len = len;
if (private->rotate == WSCONS_ROTATE_CW ||
private->rotate == WSCONS_ROTATE_CCW) {
width = private->info.height;
height = private->info.width;
} else {
width = private->info.width;
height = private->info.height;
}
if (private->shadowFB) {
private->shadowmem = (Uint8 *)malloc(len);
if (private->shadowmem == NULL) {
WSCONS_ReportError("No memory for shadow");
return -1;
}
private->fbstart = private->shadowmem;
private->fblinebytes = width * ((private->info.depth + 7) / 8);
} else {
private->fbstart = private->physmem;
private->fblinebytes = private->physlinebytes;
}
private->SDL_modelist[0] = (SDL_Rect *)malloc(sizeof(SDL_Rect));
private->SDL_modelist[0]->w = width;
private->SDL_modelist[0]->h = height;
vformat->BitsPerPixel = private->info.depth;
vformat->BytesPerPixel = private->info.depth / 8;
if (WSCONS_InitKeyboard(this) == -1) {
return -1;
}
return 0;
}
SDL_Rect **WSCONS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
{
if (format->BitsPerPixel == private->info.depth) {
return private->SDL_modelist;
} else {
return NULL;
}
}
SDL_Surface *WSCONS_SetVideoMode(_THIS, SDL_Surface *current,
int width, int height, int bpp, Uint32 flags)
{
if (width != private->SDL_modelist[0]->w ||
height != private->SDL_modelist[0]->h) {
WSCONS_ReportError("Requested video mode %dx%d not supported.",
width, height);
return NULL;
}
if (bpp != private->info.depth) {
WSCONS_ReportError("Requested video depth %d bpp not supported.", bpp);
return NULL;
}
if (!SDL_ReallocFormat(current,
bpp,
private->redMask,
private->greenMask,
private->blueMask,
0)) {
WSCONS_ReportError("Couldn't allocate new pixel format");
return NULL;
}
current->flags &= SDL_FULLSCREEN;
if (private->shadowFB) {
current->flags |= SDL_SWSURFACE;
} else {
current->flags |= SDL_HWSURFACE;
}
current->w = width;
current->h = height;
current->pitch = private->fblinebytes;
current->pixels = private->fbstart;
memset(private->fbstart, 0, private->fbmem_len);
return current;
}
static int WSCONS_AllocHWSurface(_THIS, SDL_Surface *surface)
{
return -1;
}
static void WSCONS_FreeHWSurface(_THIS, SDL_Surface *surface)
{
}
static int WSCONS_LockHWSurface(_THIS, SDL_Surface *surface)
{
return 0;
}
static void WSCONS_UnlockHWSurface(_THIS, SDL_Surface *surface)
{
}
static void WSCONS_blit16(Uint8 *byte_src_pos,
int srcRightDelta,
int srcDownDelta,
Uint8 *byte_dst_pos,
int dst_linebytes,
int width,
int height)
{
int w;
Uint16 *src_pos = (Uint16 *)byte_src_pos;
Uint16 *dst_pos = (Uint16 *)byte_dst_pos;
while (height) {
Uint16 *src = src_pos;
Uint16 *dst = dst_pos;
for (w = width; w != 0; w--) {
*dst = *src;
src += srcRightDelta;
dst++;
}
dst_pos = (Uint16 *)((Uint8 *)dst_pos + dst_linebytes);
src_pos += srcDownDelta;
height--;
}
}
#define BLOCKSIZE_W 32
#define BLOCKSIZE_H 32
static void WSCONS_blit16blocked(Uint8 *byte_src_pos,
int srcRightDelta,
int srcDownDelta,
Uint8 *byte_dst_pos,
int dst_linebytes,
int width,
int height)
{
int w;
Uint16 *src_pos = (Uint16 *)byte_src_pos;
Uint16 *dst_pos = (Uint16 *)byte_dst_pos;
while (height > 0) {
Uint16 *src = src_pos;
Uint16 *dst = dst_pos;
for (w = width; w > 0; w -= BLOCKSIZE_W) {
WSCONS_blit16((Uint8 *)src,
srcRightDelta,
srcDownDelta,
(Uint8 *)dst,
dst_linebytes,
min(w, BLOCKSIZE_W),
min(height, BLOCKSIZE_H));
src += srcRightDelta * BLOCKSIZE_W;
dst += BLOCKSIZE_W;
}
dst_pos = (Uint16 *)((Uint8 *)dst_pos + dst_linebytes * BLOCKSIZE_H);
src_pos += srcDownDelta * BLOCKSIZE_H;
height -= BLOCKSIZE_H;
}
}
static void WSCONS_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
{
int width = private->SDL_modelist[0]->w;
int height = private->SDL_modelist[0]->h;
int bytesPerPixel = (private->info.depth + 7) / 8;
int i;
if (!private->shadowFB) {
return;
}
if (private->info.depth != 16) {
WSCONS_ReportError("Shadow copy only implemented for 16 bpp");
return;
}
for (i = 0; i < numrects; i++) {
int x1, y1, x2, y2;
int scr_x1, scr_y1, scr_x2, scr_y2;
int sha_x1, sha_y1;
int shadowRightDelta; /* Address change when moving right in dest */
int shadowDownDelta; /* Address change when moving down in dest */
Uint8 *src_start;
Uint8 *dst_start;
x1 = rects[i].x;
y1 = rects[i].y;
x2 = x1 + rects[i].w;
y2 = y1 + rects[i].h;
if (x1 < 0) {
x1 = 0;
} else if (x1 > width) {
x1 = width;
}
if (x2 < 0) {
x2 = 0;
} else if (x2 > width) {
x2 = width;
}
if (y1 < 0) {
y1 = 0;
} else if (y1 > height) {
y1 = height;
}
if (y2 < 0) {
y2 = 0;
} else if (y2 > height) {
y2 = height;
}
if (x2 <= x1 || y2 <= y1) {
continue;
}
switch (private->rotate) {
case WSCONS_ROTATE_NONE:
sha_x1 = scr_x1 = x1;
sha_y1 = scr_y1 = y1;
scr_x2 = x2;
scr_y2 = y2;
shadowRightDelta = 1;
shadowDownDelta = width;
break;
case WSCONS_ROTATE_CCW:
scr_x1 = y1;
scr_y1 = width - x2;
scr_x2 = y2;
scr_y2 = width - x1;
sha_x1 = x2 - 1;
sha_y1 = y1;
shadowRightDelta = width;
shadowDownDelta = -1;
break;
case WSCONS_ROTATE_UD:
scr_x1 = width - x2;
scr_y1 = height - y2;
scr_x2 = width - x1;
scr_y2 = height - y1;
sha_x1 = x2 - 1;
sha_y1 = y2 - 1;
shadowRightDelta = -1;
shadowDownDelta = -width;
break;
case WSCONS_ROTATE_CW:
scr_x1 = height - y2;
scr_y1 = x1;
scr_x2 = height - y1;
scr_y2 = x2;
sha_x1 = x1;
sha_y1 = y2 - 1;
shadowRightDelta = -width;
shadowDownDelta = 1;
break;
default:
WSCONS_ReportError("Unknown rotation");
return;
}
src_start = private->shadowmem + (sha_y1 * width + sha_x1) * bytesPerPixel;
dst_start = private->physmem + scr_y1 * private->physlinebytes +
scr_x1 * bytesPerPixel;
private->blitFunc(src_start,
shadowRightDelta,
shadowDownDelta,
dst_start,
private->physlinebytes,
scr_x2 - scr_x1,
scr_y2 - scr_y1);
}
}
int WSCONS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
{
return 0;
}
/*
* Note: If we are terminated, this could be called in the middle of
* another SDL video routine -- notably UpdateRects.
*/
void WSCONS_VideoQuit(_THIS)
{
int mode = WSDISPLAYIO_MODE_EMUL;
if (private->shadowmem != NULL) {
free(private->shadowmem);
private->shadowmem = NULL;
}
private->fbstart = NULL;
if (this->screen != NULL) {
this->screen->pixels = NULL;
}
if (private->SDL_modelist[0] != NULL) {
free(private->SDL_modelist[0]);
private->SDL_modelist[0] = NULL;
}
if (ioctl(private->fd, WSDISPLAYIO_SMODE, &mode) == -1) {
WSCONS_ReportError("ioctl SMODE");
}
WSCONS_ReleaseKeyboard(this);
if (private->fd != -1) {
close(private->fd);
private->fd = -1;
}
}

View File

@ -0,0 +1,79 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 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@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
#ifndef _SDL_wsconsvideo_h
#define _SDL_wsconsvideo_h
#include <sys/time.h>
#include <termios.h>
#include <dev/wscons/wsconsio.h>
#include "SDL_mouse.h"
#include "SDL_sysvideo.h"
#include "SDL_mutex.h"
void WSCONS_ReportError(char *fmt, ...);
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_VideoDevice *this
#define private (this->hidden)
/* Private display data */
typedef void WSCONS_bitBlit(Uint8 *src_pos,
int srcRightDelta, // pixels, not bytes
int srcDownDelta, // pixels, not bytes
Uint8 *dst_pos,
int dst_linebytes,
int width,
int height);
struct SDL_PrivateVideoData {
int fd; /* file descriptor of open device */
struct wsdisplay_fbinfo info; /* frame buffer characteristics */
int physlinebytes; /* number of bytes per row */
int redMask, greenMask, blueMask;
Uint8 *fbstart; /* These refer to the surface used, */
int fblinebytes; /* physical frame buffer or shadow. */
size_t fbmem_len;
Uint8 *physmem;
Uint8 *shadowmem;
int rotate;
int shadowFB; /* Tells whether a shadow is being used. */
WSCONS_bitBlit *blitFunc;
SDL_Rect *SDL_modelist[2];
unsigned int kbdType;
int did_save_tty;
struct termios saved_tty;
};
#endif /* _SDL_wsconsvideo_h */