19682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/*
29682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    SDL - Simple DirectMedia Layer
39682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    Copyright (C) 1997-2012 Sam Lantinga
49682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
59682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    This library is free software; you can redistribute it and/or
69682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    modify it under the terms of the GNU Lesser General Public
79682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    License as published by the Free Software Foundation; either
89682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    version 2.1 of the License, or (at your option) any later version.
99682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    This library is distributed in the hope that it will be useful,
119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    but WITHOUT ANY WARRANTY; without even the implied warranty of
129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    Lesser General Public License for more details.
149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    You should have received a copy of the GNU Lesser General Public
169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    License along with this library; if not, write to the Free Software
179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    Sam Lantinga
209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    slouken@libsdl.org
219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall*/
229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "SDL_config.h"
239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Framebuffer console based SDL video driver implementation.
259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall*/
269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <stdio.h>
289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <fcntl.h>
299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <unistd.h>
309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <sys/ioctl.h>
319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <sys/mman.h>
329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifndef HAVE_GETPAGESIZE
349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <asm/page.h>		/* For definition of PAGE_SIZE */
359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <linux/vt.h>
389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "SDL_video.h"
409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "SDL_mouse.h"
419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "../SDL_sysvideo.h"
429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "../SDL_pixels_c.h"
439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "../../events/SDL_events_c.h"
449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "SDL_fbvideo.h"
459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "SDL_fbmouse_c.h"
469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "SDL_fbevents_c.h"
479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "SDL_fb3dfx.h"
489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "SDL_fbmatrox.h"
499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include "SDL_fbriva.h"
509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/*#define FBCON_DEBUG*/
529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(i386) && defined(FB_TYPE_VGA_PLANES)
549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define VGA16_FBCON_SUPPORT
559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#include <sys/io.h>		/* For ioperm() */
569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifndef FB_AUX_VGA_PLANES_VGA4
579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define FB_AUX_VGA_PLANES_VGA4	0
589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/*
609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic inline void outb (unsigned char value, unsigned short port)
619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall  __asm__ __volatile__ ("outb %b0,%w1"::"a" (value), "Nd" (port));
639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall*/
659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif /* FB_TYPE_VGA_PLANES */
669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* A list of video resolutions that we query for (sorted largest to smallest) */
689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic const SDL_Rect checkres[] = {
699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0, 1600, 1200 },		/* 16 bpp: 0x11E, or 286 */
709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0, 1408, 1056 },		/* 16 bpp: 0x19A, or 410 */
719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0, 1280, 1024 },		/* 16 bpp: 0x11A, or 282 */
729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0, 1152,  864 },		/* 16 bpp: 0x192, or 402 */
739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0, 1024,  768 },		/* 16 bpp: 0x117, or 279 */
749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0,  960,  720 },		/* 16 bpp: 0x18A, or 394 */
759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0,  800,  600 },		/* 16 bpp: 0x114, or 276 */
769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0,  768,  576 },		/* 16 bpp: 0x182, or 386 */
779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0,  720,  576 },		/* PAL */
789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0,  720,  480 },		/* NTSC */
799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0,  640,  480 },		/* 16 bpp: 0x111, or 273 */
809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0,  640,  400 },		/*  8 bpp: 0x100, or 256 */
819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0,  512,  384 },
829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0,  320,  240 },
839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  0, 0,  320,  200 }
849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall};
859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic const struct {
869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int xres;
879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int yres;
889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int pixclock;
899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int left;
909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int right;
919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int upper;
929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int lower;
939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int hslen;
949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int vslen;
959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int sync;
969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int vmode;
979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall} vesa_timings[] = {
989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef USE_VESA_TIMINGS	/* Only tested on Matrox Millenium I */
999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  640,  400, 39771,  48, 16, 39,  8,  96, 2, 2, 0 },	/* 70 Hz */
1009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  640,  480, 39683,  48, 16, 33, 10,  96, 2, 0, 0 },	/* 60 Hz */
1019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  768,  576, 26101, 144, 16, 28,  6, 112, 4, 0, 0 },	/* 60 Hz */
1029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  800,  600, 24038, 144, 24, 28,  8, 112, 6, 0, 0 },	/* 60 Hz */
1039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  960,  720, 17686, 144, 24, 28,  8, 112, 4, 0, 0 },	/* 60 Hz */
1049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ 1024,  768, 15386, 160, 32, 30,  4, 128, 4, 0, 0 },	/* 60 Hz */
1059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ 1152,  864, 12286, 192, 32, 30,  4, 128, 4, 0, 0 },	/* 60 Hz */
1069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ 1280, 1024,  9369, 224, 32, 32,  4, 136, 4, 0, 0 },	/* 60 Hz */
1079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ 1408, 1056,  8214, 256, 40, 32,  5, 144, 5, 0, 0 },	/* 60 Hz */
1089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ 1600, 1200,/*?*/0, 272, 48, 32,  5, 152, 5, 0, 0 },	/* 60 Hz */
1099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#else
1109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* You can generate these timings from your XF86Config file using
1119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   the 'modeline2fb' perl script included with the fbset package.
1129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   These timings were generated for Matrox Millenium I, 15" monitor.
1139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	*/
1149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  320,  200, 79440,  16, 16, 20,  4,  48, 1, 0, 2 },	/* 70 Hz */
1159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  320,  240, 63492,  16, 16, 16,  4,  48, 2, 0, 2 },	/* 72 Hz */
1169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  512,  384, 49603,  48, 16, 16,  1,  64, 3, 0, 0 },	/* 78 Hz */
1179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  640,  400, 31746,  96, 32, 41,  1,  64, 3, 2, 0 },	/* 85 Hz */
1189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  640,  480, 31746, 120, 16, 16,  1,  64, 3, 0, 0 },	/* 75 Hz */
1199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  768,  576, 26101, 144, 16, 28,  6, 112, 4, 0, 0 },	/* 60 Hz */
1209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  800,  600, 20000,  64, 56, 23, 37, 120, 6, 3, 0 },	/* 72 Hz */
1219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{  960,  720, 17686, 144, 24, 28,  8, 112, 4, 0, 0 },	/* 60 Hz */
1229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ 1024,  768, 13333, 144, 24, 29,  3, 136, 6, 0, 0 },	/* 70 Hz */
1239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ 1152,  864, 12286, 192, 32, 30,  4, 128, 4, 0, 0 },	/* 60 Hz */
1249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ 1280, 1024,  9369, 224, 32, 32,  4, 136, 4, 0, 0 },	/* 60 Hz */
1259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ 1408, 1056,  8214, 256, 40, 32,  5, 144, 5, 0, 0 },	/* 60 Hz */
1269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ 1600, 1200,/*?*/0, 272, 48, 32,  5, 152, 5, 0, 0 },	/* 60 Hz */
1279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
1289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall};
1299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallenum {
1309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FBCON_ROTATE_NONE = 0,
1319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FBCON_ROTATE_CCW = 90,
1329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FBCON_ROTATE_UD = 180,
1339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FBCON_ROTATE_CW = 270
1349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall};
1359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define min(a,b) ((a)<(b)?(a):(b))
1379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Initialization/Query functions */
1399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_VideoInit(_THIS, SDL_PixelFormat *vformat);
1409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
1419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
1429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef VGA16_FBCON_SUPPORT
1439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic SDL_Surface *FB_SetVGA16Mode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
1449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
1459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
1469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_VideoQuit(_THIS);
1479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Hardware surface functions */
1499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_InitHWSurfaces(_THIS, SDL_Surface *screen, char *base, int size);
1509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_FreeHWSurfaces(_THIS);
1519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_AllocHWSurface(_THIS, SDL_Surface *surface);
1529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_LockHWSurface(_THIS, SDL_Surface *surface);
1539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_UnlockHWSurface(_THIS, SDL_Surface *surface);
1549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_FreeHWSurface(_THIS, SDL_Surface *surface);
1559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_WaitVBL(_THIS);
1569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_WaitIdle(_THIS);
1579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_FlipHWSurface(_THIS, SDL_Surface *surface);
1589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Internal palette functions */
1609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_SavePalette(_THIS, struct fb_fix_screeninfo *finfo,
1619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                                  struct fb_var_screeninfo *vinfo);
1629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_RestorePalette(_THIS);
1639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Shadow buffer functions */
1659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic FB_bitBlit FB_blit16;
1669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic FB_bitBlit FB_blit16blocked;
1679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int SDL_getpagesize(void)
1699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
1709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef HAVE_GETPAGESIZE
1719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return getpagesize();
1729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#elif defined(PAGE_SIZE)
1739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return PAGE_SIZE;
1749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#else
1759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#error Can not determine system page size.
1769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return 4096;  /* this is what it USED to be in Linux... */
1779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
1789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Small wrapper for mmap() so we can play nicely with no-mmu hosts
1829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall * (non-mmu hosts disallow the MAP_SHARED flag) */
1839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void *do_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
1859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
1869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	void *ret;
1879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	ret = mmap(start, length, prot, flags, fd, offset);
1889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ret == (char *)-1 && (flags & MAP_SHARED) ) {
1899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		ret = mmap(start, length, prot,
1909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		           (flags & ~MAP_SHARED) | MAP_PRIVATE, fd, offset);
1919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
1929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return ret;
1939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* FB driver bootstrap functions */
1969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
1979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_Available(void)
1989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
1999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int console = -1;
2009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Added check for /fb/0 (devfs) */
2019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* but - use environment variable first... if it fails, still check defaults */
2029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int idx = 0;
2039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	const char *SDL_fbdevs[4] = { NULL, "/dev/fb0", "/dev/fb/0", NULL };
2049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_fbdevs[0] = SDL_getenv("SDL_FBDEV");
2069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if( !SDL_fbdevs[0] )
2079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		idx++;
2089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for( ; SDL_fbdevs[idx]; idx++ )
2099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{
2109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		console = open(SDL_fbdevs[idx], O_RDWR, 0);
2119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( console >= 0 ) {
2129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			close(console);
2139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
2149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
2169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(console >= 0);
2179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
2189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_DeleteDevice(SDL_VideoDevice *device)
2209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
2219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_free(device->hidden);
2229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_free(device);
2239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
2249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic SDL_VideoDevice *FB_CreateDevice(int devindex)
2269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
2279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_VideoDevice *this;
2289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Initialize all variables that we clean on shutdown */
2309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
2319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( this ) {
2329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_memset(this, 0, (sizeof *this));
2339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		this->hidden = (struct SDL_PrivateVideoData *)
2349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				SDL_malloc((sizeof *this->hidden));
2359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
2369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( (this == NULL) || (this->hidden == NULL) ) {
2379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_OutOfMemory();
2389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( this ) {
2399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_free(this);
2409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
2419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(0);
2429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
2439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_memset(this->hidden, 0, (sizeof *this->hidden));
2449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	wait_vbl = FB_WaitVBL;
2459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	wait_idle = FB_WaitIdle;
2469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mouse_fd = -1;
2479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	keyboard_fd = -1;
2489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set the function pointers */
2509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->VideoInit = FB_VideoInit;
2519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->ListModes = FB_ListModes;
2529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->SetVideoMode = FB_SetVideoMode;
2539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->SetColors = FB_SetColors;
2549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->UpdateRects = NULL;
2559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->VideoQuit = FB_VideoQuit;
2569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->AllocHWSurface = FB_AllocHWSurface;
2579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->CheckHWBlit = NULL;
2589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->FillHWRect = NULL;
2599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->SetHWColorKey = NULL;
2609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->SetHWAlpha = NULL;
2619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->LockHWSurface = FB_LockHWSurface;
2629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->UnlockHWSurface = FB_UnlockHWSurface;
2639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->FlipHWSurface = FB_FlipHWSurface;
2649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->FreeHWSurface = FB_FreeHWSurface;
2659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->SetCaption = NULL;
2669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->SetIcon = NULL;
2679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->IconifyWindow = NULL;
2689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->GrabInput = NULL;
2699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->GetWMInfo = NULL;
2709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->InitOSKeymap = FB_InitOSKeymap;
2719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->PumpEvents = FB_PumpEvents;
2729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->free = FB_DeleteDevice;
2749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return this;
2769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
2779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse HallVideoBootStrap FBCON_bootstrap = {
2799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	"fbcon", "Linux Framebuffer Console",
2809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_Available, FB_CreateDevice
2819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall};
2829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define FB_MODES_DB	"/etc/fb.modes"
2849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int read_fbmodes_line(FILE*f, char* line, int length)
2869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
2879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int blank;
2889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	char* c;
2899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int i;
2909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
2919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	blank=0;
2929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* find a relevant line */
2939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	do
2949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{
2959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (!fgets(line,length,f))
2969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return 0;
2979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		c=line;
2989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		while(((*c=='\t')||(*c==' '))&&(*c!=0))
2999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			c++;
3009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ((*c=='\n')||(*c=='#')||(*c==0))
3029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			blank=1;
3039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		else
3049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			blank=0;
3059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
3069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	while(blank);
3079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* remove whitespace at the begining of the string */
3089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	i=0;
3099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	do
3109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{
3119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		line[i]=c[i];
3129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		i++;
3139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
3149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	while(c[i]!=0);
3159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return 1;
3169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
3179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int read_fbmodes_mode(FILE *f, struct fb_var_screeninfo *vinfo)
3199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
3209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	char line[1024];
3219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	char option[256];
3229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Find a "geometry" */
3249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	do {
3259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (read_fbmodes_line(f, line, sizeof(line))==0)
3269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return 0;
3279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (SDL_strncmp(line,"geometry",8)==0)
3289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
3299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
3309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	while(1);
3319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_sscanf(line, "geometry %d %d %d %d %d", &vinfo->xres, &vinfo->yres,
3339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			&vinfo->xres_virtual, &vinfo->yres_virtual, &vinfo->bits_per_pixel);
3349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (read_fbmodes_line(f, line, sizeof(line))==0)
3359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return 0;
3369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_sscanf(line, "timings %d %d %d %d %d %d %d", &vinfo->pixclock,
3389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			&vinfo->left_margin, &vinfo->right_margin, &vinfo->upper_margin,
3399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			&vinfo->lower_margin, &vinfo->hsync_len, &vinfo->vsync_len);
3409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vinfo->sync=0;
3429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vinfo->vmode=FB_VMODE_NONINTERLACED;
3439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Parse misc options */
3459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	do {
3469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (read_fbmodes_line(f, line, sizeof(line))==0)
3479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return 0;
3489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (SDL_strncmp(line,"hsync",5)==0) {
3509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_sscanf(line,"hsync %s",option);
3519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if (SDL_strncmp(option,"high",4)==0)
3529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->sync |= FB_SYNC_HOR_HIGH_ACT;
3539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
3549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		else if (SDL_strncmp(line,"vsync",5)==0) {
3559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_sscanf(line,"vsync %s",option);
3569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if (SDL_strncmp(option,"high",4)==0)
3579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->sync |= FB_SYNC_VERT_HIGH_ACT;
3589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
3599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		else if (SDL_strncmp(line,"csync",5)==0) {
3609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_sscanf(line,"csync %s",option);
3619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if (SDL_strncmp(option,"high",4)==0)
3629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->sync |= FB_SYNC_COMP_HIGH_ACT;
3639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
3649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		else if (SDL_strncmp(line,"extsync",5)==0) {
3659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_sscanf(line,"extsync %s",option);
3669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if (SDL_strncmp(option,"true",4)==0)
3679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->sync |= FB_SYNC_EXT;
3689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
3699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		else if (SDL_strncmp(line,"laced",5)==0) {
3709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_sscanf(line,"laced %s",option);
3719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if (SDL_strncmp(option,"true",4)==0)
3729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->vmode |= FB_VMODE_INTERLACED;
3739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
3749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		else if (SDL_strncmp(line,"double",6)==0) {
3759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_sscanf(line,"double %s",option);
3769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if (SDL_strncmp(option,"true",4)==0)
3779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->vmode |= FB_VMODE_DOUBLE;
3789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
3799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
3809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	while(SDL_strncmp(line,"endmode",7)!=0);
3819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return 1;
3839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
3849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_CheckMode(_THIS, struct fb_var_screeninfo *vinfo,
3869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                        int index, unsigned int *w, unsigned int *h)
3879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
3889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int mode_okay;
3899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
3909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mode_okay = 0;
3919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vinfo->bits_per_pixel = (index+1)*8;
3929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vinfo->xres = *w;
3939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vinfo->xres_virtual = *w;
3949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vinfo->yres = *h;
3959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vinfo->yres_virtual = *h;
3969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vinfo->activate = FB_ACTIVATE_TEST;
3979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, vinfo) == 0 ) {
3989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
3999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		fprintf(stderr, "Checked mode %dx%d at %d bpp, got mode %dx%d at %d bpp\n", *w, *h, (index+1)*8, vinfo->xres, vinfo->yres, vinfo->bits_per_pixel);
4009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
4019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( (((vinfo->bits_per_pixel+7)/8)-1) == index ) {
4029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			*w = vinfo->xres;
4039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			*h = vinfo->yres;
4049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			mode_okay = 1;
4059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
4069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
4079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return mode_okay;
4089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
4099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_AddMode(_THIS, int index, unsigned int w, unsigned int h, int check_timings)
4119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
4129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_Rect *mode;
4139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int i;
4149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int next_mode;
4159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Check to see if we already have this mode */
4179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( SDL_nummodes[index] > 0 ) {
4189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		mode = SDL_modelist[index][SDL_nummodes[index]-1];
4199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( (mode->w == w) && (mode->h == h) ) {
4209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
4219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			fprintf(stderr, "We already have mode %dx%d at %d bytes per pixel\n", w, h, index+1);
4229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
4239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return(0);
4249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
4259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
4269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Only allow a mode if we have a valid timing for it */
4289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( check_timings ) {
4299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		int found_timing = 0;
4309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) {
4319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if ( (w == vesa_timings[i].xres) &&
4329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			     (h == vesa_timings[i].yres) && vesa_timings[i].pixclock ) {
4339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				found_timing = 1;
4349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				break;
4359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
4369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
4379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( !found_timing ) {
4389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
4399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			fprintf(stderr, "No valid timing line for mode %dx%d\n", w, h);
4409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
4419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return(0);
4429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
4439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
4449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set up the new video mode rectangle */
4469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
4479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( mode == NULL ) {
4489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_OutOfMemory();
4499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
4509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
4519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mode->x = 0;
4529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mode->y = 0;
4539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mode->w = w;
4549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mode->h = h;
4559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
4569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "Adding mode %dx%d at %d bytes per pixel\n", w, h, index+1);
4579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
4589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Allocate the new list of modes, and fill in the new mode */
4609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	next_mode = SDL_nummodes[index];
4619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_modelist[index] = (SDL_Rect **)
4629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	       SDL_realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
4639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( SDL_modelist[index] == NULL ) {
4649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_OutOfMemory();
4659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_nummodes[index] = 0;
4669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_free(mode);
4679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
4689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
4699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_modelist[index][next_mode] = mode;
4709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_modelist[index][next_mode+1] = NULL;
4719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_nummodes[index]++;
4729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(0);
4749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
4759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int cmpmodes(const void *va, const void *vb)
4779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
4789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    const SDL_Rect *a = *(const SDL_Rect**)va;
4799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    const SDL_Rect *b = *(const SDL_Rect**)vb;
4809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if ( a->h == b->h )
4819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        return b->w - a->w;
4829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    else
4839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        return b->h - a->h;
4849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
4859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_SortModes(_THIS)
4879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
4889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int i;
4899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( i=0; i<NUM_MODELISTS; ++i ) {
4909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( SDL_nummodes[i] > 0 ) {
4919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_qsort(SDL_modelist[i], SDL_nummodes[i], sizeof *SDL_modelist[i], cmpmodes);
4929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
4939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
4949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
4959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
4969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_VideoInit(_THIS, SDL_PixelFormat *vformat)
4979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
4989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	const int pagesize = SDL_getpagesize();
4999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	struct fb_fix_screeninfo finfo;
5009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	struct fb_var_screeninfo vinfo;
5019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int i, j;
5029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int current_index;
5039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	unsigned int current_w;
5049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	unsigned int current_h;
5059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	const char *SDL_fbdev;
5069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	const char *rotation;
5079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FILE *modesdb;
5089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Initialize the library */
5109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_fbdev = SDL_getenv("SDL_FBDEV");
5119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( SDL_fbdev == NULL ) {
5129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_fbdev = "/dev/fb0";
5139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
5149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	console_fd = open(SDL_fbdev, O_RDWR, 0);
5159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( console_fd < 0 ) {
5169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Unable to open %s", SDL_fbdev);
5179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
5189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
5199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if !SDL_THREADS_DISABLED
5219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Create the hardware surface lock mutex */
5229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	hw_lock = SDL_CreateMutex();
5239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( hw_lock == NULL ) {
5249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Unable to create lock mutex");
5259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		FB_VideoQuit(this);
5269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
5279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
5289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
5299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Get the type of video hardware */
5319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
5329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Couldn't get console hardware info");
5339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		FB_VideoQuit(this);
5349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
5359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
5369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	switch (finfo.type) {
5379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		case FB_TYPE_PACKED_PIXELS:
5389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* Supported, no worries.. */
5399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
5409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef VGA16_FBCON_SUPPORT
5419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		case FB_TYPE_VGA_PLANES:
5429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* VGA16 is supported, but that's it */
5439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if ( finfo.type_aux == FB_AUX_VGA_PLANES_VGA4 ) {
5449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				if ( ioperm(0x3b4, 0x3df - 0x3b4 + 1, 1) < 0 ) {
5459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					SDL_SetError("No I/O port permissions");
5469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					FB_VideoQuit(this);
5479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					return(-1);
5489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				}
5499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				this->SetVideoMode = FB_SetVGA16Mode;
5509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				break;
5519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
5529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* Fall through to unsupported case */
5539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif /* VGA16_FBCON_SUPPORT */
5549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		default:
5559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_SetError("Unsupported console hardware");
5569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_VideoQuit(this);
5579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return(-1);
5589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
5599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	switch (finfo.visual) {
5609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		case FB_VISUAL_TRUECOLOR:
5619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		case FB_VISUAL_PSEUDOCOLOR:
5629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		case FB_VISUAL_STATIC_PSEUDOCOLOR:
5639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		case FB_VISUAL_DIRECTCOLOR:
5649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
5659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		default:
5669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_SetError("Unsupported console hardware");
5679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_VideoQuit(this);
5689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return(-1);
5699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
5709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Check if the user wants to disable hardware acceleration */
5729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	{ const char *fb_accel;
5739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		fb_accel = SDL_getenv("SDL_FBACCEL");
5749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( fb_accel ) {
5759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			finfo.accel = SDL_atoi(fb_accel);
5769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
5779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
5789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Memory map the device, compensating for buggy PPC mmap() */
5809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mapped_offset = (((long)finfo.smem_start) -
5819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	                (((long)finfo.smem_start)&~(pagesize-1)));
5829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mapped_memlen = finfo.smem_len+mapped_offset;
5839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	mapped_mem = do_mmap(NULL, mapped_memlen,
5849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	                  PROT_READ|PROT_WRITE, MAP_SHARED, console_fd, 0);
5859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( mapped_mem == (char *)-1 ) {
5869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Unable to memory map the video hardware");
5879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		mapped_mem = NULL;
5889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		FB_VideoQuit(this);
5899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
5909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
5919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
5929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Determine the current screen depth */
5939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
5949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Couldn't get console pixel format");
5959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		FB_VideoQuit(this);
5969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
5979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
5989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vformat->BitsPerPixel = vinfo.bits_per_pixel;
5999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( vformat->BitsPerPixel < 8 ) {
6009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Assuming VGA16, we handle this via a shadow framebuffer */
6019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vformat->BitsPerPixel = 8;
6029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
6039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( i=0; i<vinfo.red.length; ++i ) {
6049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vformat->Rmask <<= 1;
6059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vformat->Rmask |= (0x00000001<<vinfo.red.offset);
6069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
6079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( i=0; i<vinfo.green.length; ++i ) {
6089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vformat->Gmask <<= 1;
6099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vformat->Gmask |= (0x00000001<<vinfo.green.offset);
6109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
6119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( i=0; i<vinfo.blue.length; ++i ) {
6129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vformat->Bmask <<= 1;
6139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vformat->Bmask |= (0x00000001<<vinfo.blue.offset);
6149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
6159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	saved_vinfo = vinfo;
6169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Save hardware palette, if needed */
6189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_SavePalette(this, &finfo, &vinfo);
6199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* If the I/O registers are available, memory map them so we
6219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   can take advantage of any supported hardware acceleration.
6229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	 */
6239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vinfo.accel_flags = 0;	/* Temporarily reserve registers */
6249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo);
6259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( finfo.accel && finfo.mmio_len ) {
6269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		mapped_iolen = finfo.mmio_len;
6279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		mapped_io = do_mmap(NULL, mapped_iolen, PROT_READ|PROT_WRITE,
6289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		                 MAP_SHARED, console_fd, mapped_memlen);
6299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( mapped_io == (char *)-1 ) {
6309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			/* Hmm, failed to memory map I/O registers */
6319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			mapped_io = NULL;
6329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
6339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
6349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	rotate = FBCON_ROTATE_NONE;
6369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	rotation = SDL_getenv("SDL_VIDEO_FBCON_ROTATION");
6379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (rotation != NULL) {
6389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (SDL_strlen(rotation) == 0) {
6399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			shadow_fb = 0;
6409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			rotate = FBCON_ROTATE_NONE;
6419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
6429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			printf("Not rotating, no shadow\n");
6439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
6449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else if (!SDL_strcmp(rotation, "NONE")) {
6459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			shadow_fb = 1;
6469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			rotate = FBCON_ROTATE_NONE;
6479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
6489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			printf("Not rotating, but still using shadow\n");
6499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
6509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else if (!SDL_strcmp(rotation, "CW")) {
6519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			shadow_fb = 1;
6529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			rotate = FBCON_ROTATE_CW;
6539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
6549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			printf("Rotating screen clockwise\n");
6559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
6569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else if (!SDL_strcmp(rotation, "CCW")) {
6579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			shadow_fb = 1;
6589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			rotate = FBCON_ROTATE_CCW;
6599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
6609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			printf("Rotating screen counter clockwise\n");
6619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
6629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else if (!SDL_strcmp(rotation, "UD")) {
6639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			shadow_fb = 1;
6649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			rotate = FBCON_ROTATE_UD;
6659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
6669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			printf("Rotating screen upside down\n");
6679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
6689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else {
6699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_SetError("\"%s\" is not a valid value for "
6709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				 "SDL_VIDEO_FBCON_ROTATION", rotation);
6719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return(-1);
6729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
6739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
6749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (rotate == FBCON_ROTATE_CW || rotate == FBCON_ROTATE_CCW) {
6769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current_w = vinfo.yres;
6779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current_h = vinfo.xres;
6789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	} else {
6799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current_w = vinfo.xres;
6809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current_h = vinfo.yres;
6819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
6829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Query for the list of available video modes */
6849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	current_index = ((vinfo.bits_per_pixel+7)/8)-1;
6859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	modesdb = fopen(FB_MODES_DB, "r");
6869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( i=0; i<NUM_MODELISTS; ++i ) {
6879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_nummodes[i] = 0;
6889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_modelist[i] = NULL;
6899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
6909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( SDL_getenv("SDL_FB_BROKEN_MODES") != NULL ) {
6919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		FB_AddMode(this, current_index, current_w, current_h, 0);
6929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	} else if(modesdb) {
6939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		while ( read_fbmodes_mode(modesdb, &vinfo) ) {
6949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			for ( i=0; i<NUM_MODELISTS; ++i ) {
6959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				unsigned int w, h;
6969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
6979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				if (rotate == FBCON_ROTATE_CW || rotate == FBCON_ROTATE_CCW) {
6989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					w = vinfo.yres;
6999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					h = vinfo.xres;
7009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				} else {
7019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					w = vinfo.xres;
7029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					h = vinfo.yres;
7039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				}
7049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				/* See if we are querying for the current mode */
7059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				if ( i == current_index ) {
7069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					if ( (current_w > w) || (current_h > h) ) {
7079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall						/* Only check once */
7089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall						FB_AddMode(this, i, current_w, current_h, 0);
7099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall						current_index = -1;
7109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					}
7119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				}
7129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				if ( FB_CheckMode(this, &vinfo, i, &w, &h) ) {
7139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					FB_AddMode(this, i, w, h, 0);
7149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				}
7159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
7169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
7179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		fclose(modesdb);
7189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		FB_SortModes(this);
7199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	} else {
7209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		for ( i=0; i<NUM_MODELISTS; ++i ) {
7219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			for ( j=0; j<(sizeof(checkres)/sizeof(checkres[0])); ++j ) {
7229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				unsigned int w, h;
7239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				if (rotate == FBCON_ROTATE_CW || rotate == FBCON_ROTATE_CCW) {
7259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					w = checkres[j].h;
7269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					h = checkres[j].w;
7279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				} else {
7289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					w = checkres[j].w;
7299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					h = checkres[j].h;
7309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				}
7319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				/* See if we are querying for the current mode */
7329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				if ( i == current_index ) {
7339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					if ( (current_w > w) || (current_h > h) ) {
7349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall						/* Only check once */
7359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall						FB_AddMode(this, i, current_w, current_h, 0);
7369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall						current_index = -1;
7379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					}
7389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				}
7399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				if ( FB_CheckMode(this, &vinfo, i, &w, &h) ) {
7409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					FB_AddMode(this, i, w, h, 1);
7419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				}
7429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
7439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
7449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
7459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->info.current_w = current_w;
7479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->info.current_h = current_h;
7489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->info.wm_available = 0;
7499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->info.hw_available = !shadow_fb;
7509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->info.video_mem = shadow_fb ? 0 : finfo.smem_len/1024;
7519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Fill in our hardware acceleration capabilities */
7529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( mapped_io ) {
7539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		switch (finfo.accel) {
7549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    case FB_ACCEL_MATROX_MGA2064W:
7559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    case FB_ACCEL_MATROX_MGA1064SG:
7569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    case FB_ACCEL_MATROX_MGA2164W:
7579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    case FB_ACCEL_MATROX_MGA2164W_AGP:
7589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    case FB_ACCEL_MATROX_MGAG100:
7599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    /*case FB_ACCEL_MATROX_MGAG200: G200 acceleration broken! */
7609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    case FB_ACCEL_MATROX_MGAG400:
7619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBACCEL_DEBUG
7629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			printf("Matrox hardware accelerator!\n");
7639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
7649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_MatroxAccel(this, finfo.accel);
7659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
7669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    case FB_ACCEL_3DFX_BANSHEE:
7679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBACCEL_DEBUG
7689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			printf("3DFX hardware accelerator!\n");
7699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
7709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_3DfxAccel(this, finfo.accel);
7719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
7729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    case FB_ACCEL_NV3:
7739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    case FB_ACCEL_NV4:
7749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBACCEL_DEBUG
7759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			printf("NVidia hardware accelerator!\n");
7769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
7779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_RivaAccel(this, finfo.accel);
7789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
7799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		    default:
7809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBACCEL_DEBUG
7819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			printf("Unknown hardware accelerator.\n");
7829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
7839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
7849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
7859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
7869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (shadow_fb) {
7889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		shadow_mem = (char *)SDL_malloc(mapped_memlen);
7899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (shadow_mem == NULL) {
7909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_SetError("No memory for shadow");
7919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return (-1);
7929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
7939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
7949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
7959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Enable mouse and keyboard support */
7969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( FB_OpenKeyboard(this) < 0 ) {
7979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		FB_VideoQuit(this);
7989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
7999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
8009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( FB_OpenMouse(this) < 0 ) {
8019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		const char *sdl_nomouse;
8029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		sdl_nomouse = SDL_getenv("SDL_NOMOUSE");
8049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( ! sdl_nomouse ) {
8059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_SetError("Unable to open mouse");
8069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_VideoQuit(this);
8079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return(-1);
8089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
8099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
8109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* We're done! */
8129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(0);
8139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
8149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
8169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
8179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
8189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
8199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Various screen update functions available */
8219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
8229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef VGA16_FBCON_SUPPORT
8239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_VGA16Update(_THIS, int numrects, SDL_Rect *rects);
8249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
8259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
8279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void print_vinfo(struct fb_var_screeninfo *vinfo)
8289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
8299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "Printing vinfo:\n");
8309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\txres: %d\n", vinfo->xres);
8319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tyres: %d\n", vinfo->yres);
8329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\txres_virtual: %d\n", vinfo->xres_virtual);
8339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tyres_virtual: %d\n", vinfo->yres_virtual);
8349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\txoffset: %d\n", vinfo->xoffset);
8359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tyoffset: %d\n", vinfo->yoffset);
8369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tbits_per_pixel: %d\n", vinfo->bits_per_pixel);
8379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tgrayscale: %d\n", vinfo->grayscale);
8389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tnonstd: %d\n", vinfo->nonstd);
8399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tactivate: %d\n", vinfo->activate);
8409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\theight: %d\n", vinfo->height);
8419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\twidth: %d\n", vinfo->width);
8429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\taccel_flags: %d\n", vinfo->accel_flags);
8439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tpixclock: %d\n", vinfo->pixclock);
8449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tleft_margin: %d\n", vinfo->left_margin);
8459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tright_margin: %d\n", vinfo->right_margin);
8469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tupper_margin: %d\n", vinfo->upper_margin);
8479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tlower_margin: %d\n", vinfo->lower_margin);
8489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\thsync_len: %d\n", vinfo->hsync_len);
8499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tvsync_len: %d\n", vinfo->vsync_len);
8509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tsync: %d\n", vinfo->sync);
8519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tvmode: %d\n", vinfo->vmode);
8529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tred: %d/%d\n", vinfo->red.length, vinfo->red.offset);
8539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tgreen: %d/%d\n", vinfo->green.length, vinfo->green.offset);
8549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tblue: %d/%d\n", vinfo->blue.length, vinfo->blue.offset);
8559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\talpha: %d/%d\n", vinfo->transp.length, vinfo->transp.offset);
8569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
8579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void print_finfo(struct fb_fix_screeninfo *finfo)
8589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
8599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "Printing finfo:\n");
8609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tsmem_start = %p\n", (char *)finfo->smem_start);
8619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tsmem_len = %d\n", finfo->smem_len);
8629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\ttype = %d\n", finfo->type);
8639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\ttype_aux = %d\n", finfo->type_aux);
8649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tvisual = %d\n", finfo->visual);
8659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\txpanstep = %d\n", finfo->xpanstep);
8669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\typanstep = %d\n", finfo->ypanstep);
8679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tywrapstep = %d\n", finfo->ywrapstep);
8689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tline_length = %d\n", finfo->line_length);
8699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tmmio_start = %p\n", (char *)finfo->mmio_start);
8709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\tmmio_len = %d\n", finfo->mmio_len);
8719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "\taccel = %d\n", finfo->accel);
8729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
8739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
8749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int choose_fbmodes_mode(struct fb_var_screeninfo *vinfo)
8769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
8779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int matched;
8789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FILE *modesdb;
8799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	struct fb_var_screeninfo cinfo;
8809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
8819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	matched = 0;
8829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	modesdb = fopen(FB_MODES_DB, "r");
8839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( modesdb ) {
8849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Parse the mode definition file */
8859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		while ( read_fbmodes_mode(modesdb, &cinfo) ) {
8869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if ( (vinfo->xres == cinfo.xres && vinfo->yres == cinfo.yres) &&
8879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			     (!matched || (vinfo->bits_per_pixel == cinfo.bits_per_pixel)) ) {
8889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->pixclock = cinfo.pixclock;
8899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->left_margin = cinfo.left_margin;
8909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->right_margin = cinfo.right_margin;
8919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->upper_margin = cinfo.upper_margin;
8929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->lower_margin = cinfo.lower_margin;
8939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->hsync_len = cinfo.hsync_len;
8949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->vsync_len = cinfo.vsync_len;
8959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				if ( matched ) {
8969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					break;
8979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				}
8989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				matched = 1;
8999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
9009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
9019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		fclose(modesdb);
9029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
9039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(matched);
9049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
9059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int choose_vesa_mode(struct fb_var_screeninfo *vinfo)
9079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
9089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int matched;
9099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int i;
9109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Check for VESA timings */
9129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	matched = 0;
9139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) {
9149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( (vinfo->xres == vesa_timings[i].xres) &&
9159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		     (vinfo->yres == vesa_timings[i].yres) ) {
9169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
9179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			fprintf(stderr, "Using VESA timings for %dx%d\n",
9189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall						vinfo->xres, vinfo->yres);
9199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
9209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if ( vesa_timings[i].pixclock ) {
9219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				vinfo->pixclock = vesa_timings[i].pixclock;
9229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
9239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo->left_margin = vesa_timings[i].left;
9249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo->right_margin = vesa_timings[i].right;
9259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo->upper_margin = vesa_timings[i].upper;
9269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo->lower_margin = vesa_timings[i].lower;
9279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo->hsync_len = vesa_timings[i].hslen;
9289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo->vsync_len = vesa_timings[i].vslen;
9299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo->sync = vesa_timings[i].sync;
9309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo->vmode = vesa_timings[i].vmode;
9319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			matched = 1;
9329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
9339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
9349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
9359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(matched);
9369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
9379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef VGA16_FBCON_SUPPORT
9399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic SDL_Surface *FB_SetVGA16Mode(_THIS, SDL_Surface *current,
9409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				int width, int height, int bpp, Uint32 flags)
9419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
9429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	struct fb_fix_screeninfo finfo;
9439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	struct fb_var_screeninfo vinfo;
9449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set the terminal into graphics mode */
9469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( FB_EnterGraphicsMode(this) < 0 ) {
9479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(NULL);
9489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
9499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Restore the original palette */
9519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_RestorePalette(this);
9529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set the video mode and get the final screen format */
9549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
9559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Couldn't get console screen info");
9569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(NULL);
9579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
9589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cache_vinfo = vinfo;
9599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
9609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "Printing actual vinfo:\n");
9619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	print_vinfo(&vinfo);
9629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
9639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ! SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) {
9649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(NULL);
9659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
9669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	current->format->palette->ncolors = 16;
9679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Get the fixed information about the console hardware.
9699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   This is necessary since finfo.line_length changes.
9709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	 */
9719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
9729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Couldn't get console hardware info");
9739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(NULL);
9749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
9759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
9769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "Printing actual finfo:\n");
9779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	print_finfo(&finfo);
9789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
9799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Save hardware palette, if needed */
9819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_SavePalette(this, &finfo, &vinfo);
9829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set up the new mode framebuffer */
9849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	current->flags = SDL_FULLSCREEN;
9859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	current->w = vinfo.xres;
9869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	current->h = vinfo.yres;
9879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	current->pitch = current->w;
9889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	current->pixels = SDL_malloc(current->h*current->pitch);
9899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set the update rectangle function */
9919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->UpdateRects = FB_VGA16Update;
9929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* We're done */
9949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(current);
9959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
9969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif /* VGA16_FBCON_SUPPORT */
9979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
9989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current,
9999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				int width, int height, int bpp, Uint32 flags)
10009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
10019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	struct fb_fix_screeninfo finfo;
10029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	struct fb_var_screeninfo vinfo;
10039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int i;
10049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Uint32 Rmask;
10059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Uint32 Gmask;
10069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Uint32 Bmask;
10079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	char *surfaces_mem;
10089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int surfaces_len;
10099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
10109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set the terminal into graphics mode */
10119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( FB_EnterGraphicsMode(this) < 0 ) {
10129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(NULL);
10139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
10149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
10159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Restore the original palette */
10169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_RestorePalette(this);
10179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
10189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set the video mode and get the final screen format */
10199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
10209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Couldn't get console screen info");
10219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(NULL);
10229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
10239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
10249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "Printing original vinfo:\n");
10259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	print_vinfo(&vinfo);
10269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
10279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Do not use double buffering with shadow buffer */
10289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (shadow_fb) {
10299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		flags &= ~SDL_DOUBLEBUF;
10309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
10319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
10329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( (vinfo.xres != width) || (vinfo.yres != height) ||
10339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	     (vinfo.bits_per_pixel != bpp) || (flags & SDL_DOUBLEBUF) ) {
10349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.activate = FB_ACTIVATE_NOW;
10359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.accel_flags = 0;
10369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.bits_per_pixel = bpp;
10379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.xres = width;
10389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.xres_virtual = width;
10399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.yres = height;
10409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( flags & SDL_DOUBLEBUF ) {
10419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo.yres_virtual = height*2;
10429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else {
10439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo.yres_virtual = height;
10449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
10459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.xoffset = 0;
10469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.yoffset = 0;
10479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.red.length = vinfo.red.offset = 0;
10489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.green.length = vinfo.green.offset = 0;
10499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.blue.length = vinfo.blue.offset = 0;
10509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.transp.length = vinfo.transp.offset = 0;
10519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( ! choose_fbmodes_mode(&vinfo) ) {
10529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			choose_vesa_mode(&vinfo);
10539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
10549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
10559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		fprintf(stderr, "Printing wanted vinfo:\n");
10569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		print_vinfo(&vinfo);
10579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
10589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( !shadow_fb &&
10599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {
10609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo.yres_virtual = height;
10619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {
10629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				SDL_SetError("Couldn't set console screen info");
10639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				return(NULL);
10649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
10659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
10669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	} else {
10679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		int maxheight;
10689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
10699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Figure out how much video memory is available */
10709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( flags & SDL_DOUBLEBUF ) {
10719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			maxheight = height*2;
10729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else {
10739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			maxheight = height;
10749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
10759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( vinfo.yres_virtual > maxheight ) {
10769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			vinfo.yres_virtual = maxheight;
10779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
10789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
10799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cache_vinfo = vinfo;
10809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
10819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "Printing actual vinfo:\n");
10829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	print_vinfo(&vinfo);
10839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
10849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Rmask = 0;
10859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( i=0; i<vinfo.red.length; ++i ) {
10869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Rmask <<= 1;
10879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Rmask |= (0x00000001<<vinfo.red.offset);
10889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
10899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Gmask = 0;
10909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( i=0; i<vinfo.green.length; ++i ) {
10919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Gmask <<= 1;
10929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Gmask |= (0x00000001<<vinfo.green.offset);
10939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
10949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Bmask = 0;
10959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( i=0; i<vinfo.blue.length; ++i ) {
10969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Bmask <<= 1;
10979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Bmask |= (0x00000001<<vinfo.blue.offset);
10989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
10999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ! SDL_ReallocFormat(current, vinfo.bits_per_pixel,
11009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	                                  Rmask, Gmask, Bmask, 0) ) {
11019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(NULL);
11029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
11039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Get the fixed information about the console hardware.
11059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   This is necessary since finfo.line_length changes.
11069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	 */
11079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
11089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Couldn't get console hardware info");
11099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(NULL);
11109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
11119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Save hardware palette, if needed */
11139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_SavePalette(this, &finfo, &vinfo);
11149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (shadow_fb) {
11169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (vinfo.bits_per_pixel == 16) {
11179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			blitFunc = (rotate == FBCON_ROTATE_NONE ||
11189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					rotate == FBCON_ROTATE_UD) ?
11199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				FB_blit16 : FB_blit16blocked;
11209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else {
11219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
11229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			fprintf(stderr, "Init vinfo:\n");
11239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			print_vinfo(&vinfo);
11249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
11259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_SetError("Using software buffer, but no blitter "
11269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					"function is available for %d bpp.",
11279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					vinfo.bits_per_pixel);
11289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return(NULL);
11299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
11309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
11319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set up the new mode framebuffer */
11339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	current->flags &= SDL_FULLSCREEN;
11349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (shadow_fb) {
11359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current->flags |= SDL_SWSURFACE;
11369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	} else {
11379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current->flags |= SDL_HWSURFACE;
11389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
11399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	current->w = vinfo.xres;
11409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	current->h = vinfo.yres;
11419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (shadow_fb) {
11429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current->pitch = current->w * ((vinfo.bits_per_pixel + 7) / 8);
11439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current->pixels = shadow_mem;
11449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		physlinebytes = finfo.line_length;
11459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	} else {
11469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current->pitch = finfo.line_length;
11479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current->pixels = mapped_mem+mapped_offset;
11489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
11499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set up the information for hardware surfaces */
11519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces_mem = (char *)current->pixels +
11529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vinfo.yres_virtual*current->pitch;
11539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces_len = (shadow_fb) ?
11549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		0 : (mapped_memlen-(surfaces_mem-mapped_mem));
11559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_FreeHWSurfaces(this);
11579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_InitHWSurfaces(this, current, surfaces_mem, surfaces_len);
11589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Let the application know we have a hardware palette */
11609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	switch (finfo.visual) {
11619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		case FB_VISUAL_PSEUDOCOLOR:
11629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		current->flags |= SDL_HWPALETTE;
11639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		break;
11649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		default:
11659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		break;
11669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
11679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Update for double-buffering, if we can */
11699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( flags & SDL_DOUBLEBUF ) {
11709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( vinfo.yres_virtual == (height*2) ) {
11719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			current->flags |= SDL_DOUBLEBUF;
11729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			flip_page = 0;
11739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			flip_address[0] = (char *)current->pixels;
11749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			flip_address[1] = (char *)current->pixels+
11759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				current->h*current->pitch;
11769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			this->screen = current;
11779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_FlipHWSurface(this, current);
11789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			this->screen = NULL;
11799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
11809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
11819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set the update rectangle function */
11839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	this->UpdateRects = FB_DirectUpdate;
11849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* We're done */
11869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(current);
11879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
11889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
11909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallvoid FB_DumpHWSurfaces(_THIS)
11919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
11929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vidmem_bucket *bucket;
11939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
11949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	printf("Memory left: %d (%d total)\n", surfaces_memleft, surfaces_memtotal);
11959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	printf("\n");
11969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	printf("         Base  Size\n");
11979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
11989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		printf("Bucket:  %p, %d (%s)\n", bucket->base, bucket->size, bucket->used ? "used" : "free");
11999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( bucket->prev ) {
12009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if ( bucket->base != bucket->prev->base+bucket->prev->size ) {
12019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				printf("Warning, corrupt bucket list! (prev)\n");
12029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
12039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else {
12049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if ( bucket != &surfaces ) {
12059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				printf("Warning, corrupt bucket list! (!prev)\n");
12069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
12079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
12089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( bucket->next ) {
12099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if ( bucket->next->base != bucket->base+bucket->size ) {
12109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				printf("Warning, corrupt bucket list! (next)\n");
12119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
12129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
12139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
12149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	printf("\n");
12159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
12169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
12179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
12189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_InitHWSurfaces(_THIS, SDL_Surface *screen, char *base, int size)
12199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
12209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vidmem_bucket *bucket;
12219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
12229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces_memtotal = size;
12239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces_memleft = size;
12249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
12259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( surfaces_memleft > 0 ) {
12269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket = (vidmem_bucket *)SDL_malloc(sizeof(*bucket));
12279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( bucket == NULL ) {
12289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_OutOfMemory();
12299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return(-1);
12309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
12319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket->prev = &surfaces;
12329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket->used = 0;
12339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket->dirty = 0;
12349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket->base = base;
12359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket->size = size;
12369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket->next = NULL;
12379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	} else {
12389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket = NULL;
12399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
12409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
12419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces.prev = NULL;
12429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces.used = 1;
12439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces.dirty = 0;
12449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces.base = screen->pixels;
12459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces.size = (unsigned int)((long)base - (long)surfaces.base);
12469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces.next = bucket;
12479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	screen->hwdata = (struct private_hwdata *)&surfaces;
12489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(0);
12499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
12509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_FreeHWSurfaces(_THIS)
12519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
12529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vidmem_bucket *bucket, *freeable;
12539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
12549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	bucket = surfaces.next;
12559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	while ( bucket ) {
12569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		freeable = bucket;
12579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket = bucket->next;
12589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_free(freeable);
12599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
12609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces.next = NULL;
12619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
12629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
12639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_AllocHWSurface(_THIS, SDL_Surface *surface)
12649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
12659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vidmem_bucket *bucket;
12669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int size;
12679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int extra;
12689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
12699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Temporarily, we only allow surfaces the same width as display.
12709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   Some blitters require the pitch between two hardware surfaces
12719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   to be the same.  Others have interesting alignment restrictions.
12729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   Until someone who knows these details looks at the code...
12739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall*/
12749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallif ( surface->pitch > SDL_VideoSurface->pitch ) {
12759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	SDL_SetError("Surface requested wider than screen");
12769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(-1);
12779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
12789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallsurface->pitch = SDL_VideoSurface->pitch;
12799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	size = surface->h * surface->pitch;
12809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
12819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "Allocating bucket of %d bytes\n", size);
12829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
12839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
12849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Quick check for available mem */
12859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( size > surfaces_memleft ) {
12869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Not enough video memory");
12879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
12889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
12899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
12909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Search for an empty bucket big enough */
12919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
12929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( ! bucket->used && (size <= bucket->size) ) {
12939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
12949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
12959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
12969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( bucket == NULL ) {
12979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Video memory too fragmented");
12989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
12999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
13009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
13019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Create a new bucket for left-over memory */
13029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	extra = (bucket->size - size);
13039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( extra ) {
13049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		vidmem_bucket *newbucket;
13059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
13069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
13079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "Adding new free bucket of %d bytes\n", extra);
13089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
13099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		newbucket = (vidmem_bucket *)SDL_malloc(sizeof(*newbucket));
13109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( newbucket == NULL ) {
13119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_OutOfMemory();
13129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			return(-1);
13139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
13149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		newbucket->prev = bucket;
13159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		newbucket->used = 0;
13169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		newbucket->base = bucket->base+size;
13179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		newbucket->size = extra;
13189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		newbucket->next = bucket->next;
13199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( bucket->next ) {
13209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			bucket->next->prev = newbucket;
13219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
13229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket->next = newbucket;
13239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
13249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
13259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set the current bucket values and return it! */
13269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	bucket->used = 1;
13279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	bucket->size = size;
13289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	bucket->dirty = 0;
13299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBCON_DEBUG
13309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	fprintf(stderr, "Allocated %d bytes at %p\n", bucket->size, bucket->base);
13319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
13329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surfaces_memleft -= size;
13339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surface->flags |= SDL_HWSURFACE;
13349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surface->pixels = bucket->base;
13359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surface->hwdata = (struct private_hwdata *)bucket;
13369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(0);
13379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
13389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_FreeHWSurface(_THIS, SDL_Surface *surface)
13399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
13409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	vidmem_bucket *bucket, *freeable;
13419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
13429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Look for the bucket in the current list */
13439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
13449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( bucket == (vidmem_bucket *)surface->hwdata ) {
13459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			break;
13469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
13479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
13489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( bucket && bucket->used ) {
13499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Add the memory back to the total */
13509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef DGA_DEBUG
13519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	printf("Freeing bucket of %d bytes\n", bucket->size);
13529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
13539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		surfaces_memleft += bucket->size;
13549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
13559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Can we merge the space with surrounding buckets? */
13569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		bucket->used = 0;
13579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( bucket->next && ! bucket->next->used ) {
13589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef DGA_DEBUG
13599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	printf("Merging with next bucket, for %d total bytes\n", bucket->size+bucket->next->size);
13609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
13619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			freeable = bucket->next;
13629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			bucket->size += bucket->next->size;
13639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			bucket->next = bucket->next->next;
13649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if ( bucket->next ) {
13659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				bucket->next->prev = bucket;
13669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
13679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_free(freeable);
13689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
13699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( bucket->prev && ! bucket->prev->used ) {
13709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef DGA_DEBUG
13719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	printf("Merging with previous bucket, for %d total bytes\n", bucket->prev->size+bucket->size);
13729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
13739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			freeable = bucket;
13749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			bucket->prev->size += bucket->size;
13759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			bucket->prev->next = bucket->next;
13769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			if ( bucket->next ) {
13779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				bucket->next->prev = bucket->prev;
13789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
13799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_free(freeable);
13809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
13819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
13829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surface->pixels = NULL;
13839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surface->hwdata = NULL;
13849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
13859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
13869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_LockHWSurface(_THIS, SDL_Surface *surface)
13879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
13889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( switched_away ) {
13899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return -2; /* no hardware access */
13909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
13919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( surface == this->screen ) {
13929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_mutexP(hw_lock);
13939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( FB_IsSurfaceBusy(surface) ) {
13949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_WaitBusySurfaces(this);
13959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
13969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	} else {
13979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( FB_IsSurfaceBusy(surface) ) {
13989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_WaitBusySurfaces(this);
13999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
14009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
14019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(0);
14029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
14039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_UnlockHWSurface(_THIS, SDL_Surface *surface)
14049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
14059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( surface == this->screen ) {
14069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_mutexV(hw_lock);
14079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
14089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
14099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_WaitVBL(_THIS)
14119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
14129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef FBIOWAITRETRACE /* Heheh, this didn't make it into the main kernel */
14139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	ioctl(console_fd, FBIOWAITRETRACE, 0);
14149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
14159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return;
14169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
14179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_WaitIdle(_THIS)
14199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
14209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return;
14219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
14229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_FlipHWSurface(_THIS, SDL_Surface *surface)
14249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
14259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( switched_away ) {
14269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return -2; /* no hardware access */
14279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
14289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Wait for vertical retrace and then flip display */
14309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cache_vinfo.yoffset = flip_page*surface->h;
14319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( FB_IsSurfaceBusy(this->screen) ) {
14329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		FB_WaitBusySurfaces(this);
14339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
14349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	wait_vbl(this);
14359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( ioctl(console_fd, FBIOPAN_DISPLAY, &cache_vinfo) < 0 ) {
14369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("ioctl(FBIOPAN_DISPLAY) failed");
14379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(-1);
14389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
14399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	flip_page = !flip_page;
14409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	surface->pixels = flip_address[flip_page];
14429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(0);
14439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
14449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_blit16(Uint8 *byte_src_pos, int src_right_delta, int src_down_delta,
14469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Uint8 *byte_dst_pos, int dst_linebytes, int width, int height)
14479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
14489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int w;
14499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Uint16 *src_pos = (Uint16 *)byte_src_pos;
14509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Uint16 *dst_pos = (Uint16 *)byte_dst_pos;
14519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	while (height) {
14539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Uint16 *src = src_pos;
14549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Uint16 *dst = dst_pos;
14559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		for (w = width; w != 0; w--) {
14569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			*dst = *src;
14579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			src += src_right_delta;
14589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			dst++;
14599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
14609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		dst_pos = (Uint16 *)((Uint8 *)dst_pos + dst_linebytes);
14619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		src_pos += src_down_delta;
14629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		height--;
14639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
14649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
14659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define BLOCKSIZE_W 32
14679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define BLOCKSIZE_H 32
14689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_blit16blocked(Uint8 *byte_src_pos, int src_right_delta, int src_down_delta,
14709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Uint8 *byte_dst_pos, int dst_linebytes, int width, int height)
14719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
14729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int w;
14739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Uint16 *src_pos = (Uint16 *)byte_src_pos;
14749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	Uint16 *dst_pos = (Uint16 *)byte_dst_pos;
14759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	while (height > 0) {
14779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Uint16 *src = src_pos;
14789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		Uint16 *dst = dst_pos;
14799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		for (w = width; w > 0; w -= BLOCKSIZE_W) {
14809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_blit16((Uint8 *)src,
14819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					src_right_delta,
14829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					src_down_delta,
14839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					(Uint8 *)dst,
14849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					dst_linebytes,
14859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					min(w, BLOCKSIZE_W),
14869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall					min(height, BLOCKSIZE_H));
14879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			src += src_right_delta * BLOCKSIZE_W;
14889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			dst += BLOCKSIZE_W;
14899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
14909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		dst_pos = (Uint16 *)((Uint8 *)dst_pos + dst_linebytes * BLOCKSIZE_H);
14919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		src_pos += src_down_delta * BLOCKSIZE_H;
14929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		height -= BLOCKSIZE_H;
14939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
14949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
14959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
14969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
14979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
14989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int width = cache_vinfo.xres;
14999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int height = cache_vinfo.yres;
15009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int bytes_per_pixel = (cache_vinfo.bits_per_pixel + 7) / 8;
15019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int i;
15029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
15039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (!shadow_fb) {
15049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* The application is already updating the visible video memory */
15059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return;
15069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
15079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
15089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if (cache_vinfo.bits_per_pixel != 16) {
15099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_SetError("Shadow copy only implemented for 16 bpp");
15109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return;
15119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
15129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
15139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for (i = 0; i < numrects; i++) {
15149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		int x1, y1, x2, y2;
15159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		int scr_x1, scr_y1, scr_x2, scr_y2;
15169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		int sha_x1, sha_y1;
15179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		int shadow_right_delta;  /* Address change when moving right in dest */
15189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		int shadow_down_delta;   /* Address change when moving down in dest */
15199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		char *src_start;
15209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		char *dst_start;
15219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
15229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		x1 = rects[i].x;
15239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		y1 = rects[i].y;
15249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		x2 = x1 + rects[i].w;
15259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		y2 = y1 + rects[i].h;
15269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
15279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (x1 < 0) {
15289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			x1 = 0;
15299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else if (x1 > width) {
15309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			x1 = width;
15319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
15329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (x2 < 0) {
15339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			x2 = 0;
15349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else if (x2 > width) {
15359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			x2 = width;
15369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
15379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (y1 < 0) {
15389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			y1 = 0;
15399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else if (y1 > height) {
15409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			y1 = height;
15419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
15429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (y2 < 0) {
15439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			y2 = 0;
15449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		} else if (y2 > height) {
15459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			y2 = height;
15469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
15479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if (x2 <= x1 || y2 <= y1) {
15489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			continue;
15499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
15509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
15519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		switch (rotate) {
15529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			case FBCON_ROTATE_NONE:
15539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				sha_x1 = scr_x1 = x1;
15549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				sha_y1 = scr_y1 = y1;
15559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_x2 = x2;
15569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_y2 = y2;
15579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				shadow_right_delta = 1;
15589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				shadow_down_delta = width;
15599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				break;
15609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			case FBCON_ROTATE_CCW:
15619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_x1 = y1;
15629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_y1 = width - x2;
15639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_x2 = y2;
15649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_y2 = width - x1;
15659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				sha_x1 = x2 - 1;
15669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				sha_y1 = y1;
15679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				shadow_right_delta = width;
15689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				shadow_down_delta = -1;
15699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				break;
15709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			case FBCON_ROTATE_UD:
15719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_x1 = width - x2;
15729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_y1 = height - y2;
15739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_x2 = width - x1;
15749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_y2 = height - y1;
15759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				sha_x1 = x2 - 1;
15769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				sha_y1 = y2 - 1;
15779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				shadow_right_delta = -1;
15789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				shadow_down_delta = -width;
15799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				break;
15809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			case FBCON_ROTATE_CW:
15819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_x1 = height - y2;
15829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_y1 = x1;
15839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_x2 = height - y1;
15849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_y2 = x2;
15859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				sha_x1 = x1;
15869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				sha_y1 = y2 - 1;
15879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				shadow_right_delta = -width;
15889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				shadow_down_delta = 1;
15899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				break;
15909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			default:
15919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				SDL_SetError("Unknown rotation");
15929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				return;
15939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
15949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
15959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		src_start = shadow_mem +
15969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			(sha_y1 * width + sha_x1) * bytes_per_pixel;
15979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		dst_start = mapped_mem + mapped_offset + scr_y1 * physlinebytes +
15989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			scr_x1 * bytes_per_pixel;
15999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
16009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		blitFunc((Uint8 *) src_start,
16019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				shadow_right_delta,
16029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				shadow_down_delta,
16039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				(Uint8 *) dst_start,
16049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				physlinebytes,
16059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_x2 - scr_x1,
16069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				scr_y2 - scr_y1);
16079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
16089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
16099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
16109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#ifdef VGA16_FBCON_SUPPORT
16119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Code adapted with thanks from the XFree86 VGA16 driver! :) */
16129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define writeGr(index, value) \
16139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Halloutb(index, 0x3CE);           \
16149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Halloutb(value, 0x3CF);
16159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#define writeSeq(index, value) \
16169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Halloutb(index, 0x3C4);            \
16179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Halloutb(value, 0x3C5);
16189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
16199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_VGA16Update(_THIS, int numrects, SDL_Rect *rects)
16209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
16219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    SDL_Surface *screen;
16229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    int width, height, FBPitch, left, i, j, SRCPitch, phase;
16239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    register Uint32 m;
16249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    Uint8  s1, s2, s3, s4;
16259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    Uint32 *src, *srcPtr;
16269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    Uint8  *dst, *dstPtr;
16279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
16289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    if ( switched_away ) {
16299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        return; /* no hardware access */
16309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
16319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
16329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    screen = this->screen;
16339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    FBPitch = screen->w >> 3;
16349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    SRCPitch = screen->pitch >> 2;
16359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
16369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    writeGr(0x03, 0x00);
16379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    writeGr(0x05, 0x00);
16389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    writeGr(0x01, 0x00);
16399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    writeGr(0x08, 0xFF);
16409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
16419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    while(numrects--) {
16429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	left = rects->x & ~7;
16439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        width = (rects->w + 7) >> 3;
16449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        height = rects->h;
16459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        src = (Uint32*)screen->pixels + (rects->y * SRCPitch) + (left >> 2);
16469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        dst = (Uint8*)mapped_mem + (rects->y * FBPitch) + (left >> 3);
16479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
16489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if((phase = (long)dst & 3L)) {
16499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    phase = 4 - phase;
16509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    if(phase > width) phase = width;
16519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    width -= phase;
16529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
16539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
16549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        while(height--) {
16559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    writeSeq(0x02, 1 << 0);
16569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    dstPtr = dst;
16579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    srcPtr = src;
16589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    i = width;
16599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    j = phase;
16609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(j--) {
16619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4);
16629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		*dstPtr++ = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
16639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 2;
16649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
16659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(i >= 4) {
16669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4);
16679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s1 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
16689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[3] & 0x01010101) | ((srcPtr[2] & 0x01010101) << 4);
16699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s2 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
16709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[5] & 0x01010101) | ((srcPtr[4] & 0x01010101) << 4);
16719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s3 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
16729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[7] & 0x01010101) | ((srcPtr[6] & 0x01010101) << 4);
16739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s4 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
16749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		*((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
16759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 8;
16769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		dstPtr += 4;
16779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		i -= 4;
16789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
16799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(i--) {
16809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4);
16819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		*dstPtr++ = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
16829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 2;
16839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
16849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
16859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    writeSeq(0x02, 1 << 1);
16869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    dstPtr = dst;
16879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    srcPtr = src;
16889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    i = width;
16899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    j = phase;
16909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(j--) {
16919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4);
16929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		*dstPtr++ = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
16939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 2;
16949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
16959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(i >= 4) {
16969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4);
16979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s1 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
16989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[3] & 0x02020202) | ((srcPtr[2] & 0x02020202) << 4);
16999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s2 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
17009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[5] & 0x02020202) | ((srcPtr[4] & 0x02020202) << 4);
17019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s3 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
17029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[7] & 0x02020202) | ((srcPtr[6] & 0x02020202) << 4);
17039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s4 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
17049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		*((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
17059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 8;
17069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		dstPtr += 4;
17079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		i -= 4;
17089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
17099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(i--) {
17109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4);
17119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		*dstPtr++ = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
17129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 2;
17139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
17149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
17159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    writeSeq(0x02, 1 << 2);
17169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    dstPtr = dst;
17179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    srcPtr = src;
17189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    i = width;
17199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    j = phase;
17209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(j--) {
17219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4);
17229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		*dstPtr++ = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
17239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 2;
17249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
17259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(i >= 4) {
17269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4);
17279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s1 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
17289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[3] & 0x04040404) | ((srcPtr[2] & 0x04040404) << 4);
17299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s2 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
17309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[5] & 0x04040404) | ((srcPtr[4] & 0x04040404) << 4);
17319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s3 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
17329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[7] & 0x04040404) | ((srcPtr[6] & 0x04040404) << 4);
17339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s4 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
17349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		*((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
17359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 8;
17369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		dstPtr += 4;
17379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		i -= 4;
17389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
17399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(i--) {
17409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4);
17419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		*dstPtr++ = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
17429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 2;
17439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
17449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
17459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    writeSeq(0x02, 1 << 3);
17469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    dstPtr = dst;
17479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    srcPtr = src;
17489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    i = width;
17499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    j = phase;
17509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(j--) {
17519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4);
17529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		*dstPtr++ = (m >> 27) | (m >> 18) | (m >> 9) | m;
17539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 2;
17549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
17559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(i >= 4) {
17569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4);
17579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s1 = (m >> 27) | (m >> 18) | (m >> 9) | m;
17589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[3] & 0x08080808) | ((srcPtr[2] & 0x08080808) << 4);
17599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s2 = (m >> 27) | (m >> 18) | (m >> 9) | m;
17609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[5] & 0x08080808) | ((srcPtr[4] & 0x08080808) << 4);
17619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s3 = (m >> 27) | (m >> 18) | (m >> 9) | m;
17629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[7] & 0x08080808) | ((srcPtr[6] & 0x08080808) << 4);
17639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		s4 = (m >> 27) | (m >> 18) | (m >> 9) | m;
17649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		*((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
17659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 8;
17669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		dstPtr += 4;
17679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		i -= 4;
17689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
17699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    while(i--) {
17709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4);
17719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall 		*dstPtr++ = (m >> 27) | (m >> 18) | (m >> 9) | m;
17729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		srcPtr += 2;
17739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    }
17749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
17759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall            dst += FBPitch;
17769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall            src += SRCPitch;
17779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        }
17789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall        rects++;
17799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall    }
17809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
17819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif /* VGA16_FBCON_SUPPORT */
17829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
17839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallvoid FB_SavePaletteTo(_THIS, int palette_len, __u16 *area)
17849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
17859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	struct fb_cmap cmap;
17869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
17879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.start = 0;
17889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.len = palette_len;
17899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.red = &area[0*palette_len];
17909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.green = &area[1*palette_len];
17919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.blue = &area[2*palette_len];
17929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.transp = NULL;
17939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	ioctl(console_fd, FBIOGETCMAP, &cmap);
17949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
17959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
17969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallvoid FB_RestorePaletteFrom(_THIS, int palette_len, __u16 *area)
17979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
17989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	struct fb_cmap cmap;
17999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.start = 0;
18019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.len = palette_len;
18029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.red = &area[0*palette_len];
18039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.green = &area[1*palette_len];
18049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.blue = &area[2*palette_len];
18059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.transp = NULL;
18069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	ioctl(console_fd, FBIOPUTCMAP, &cmap);
18079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
18089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_SavePalette(_THIS, struct fb_fix_screeninfo *finfo,
18109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall                                  struct fb_var_screeninfo *vinfo)
18119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
18129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int i;
18139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Save hardware palette, if needed */
18159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( finfo->visual == FB_VISUAL_PSEUDOCOLOR ) {
18169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		saved_cmaplen = 1<<vinfo->bits_per_pixel;
18179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		saved_cmap=(__u16 *)SDL_malloc(3*saved_cmaplen*sizeof(*saved_cmap));
18189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( saved_cmap != NULL ) {
18199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_SavePaletteTo(this, saved_cmaplen, saved_cmap);
18209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
18219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
18229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Added support for FB_VISUAL_DIRECTCOLOR.
18249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   With this mode pixel information is passed through the palette...
18259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   Neat fading and gamma correction effects can be had by simply
18269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   fooling around with the palette instead of changing the pixel
18279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   values themselves... Very neat!
18289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   Adam Meyerowitz 1/19/2000
18309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	   ameyerow@optonline.com
18319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	*/
18329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( finfo->visual == FB_VISUAL_DIRECTCOLOR ) {
18339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		__u16 new_entries[3*256];
18349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Save the colormap */
18369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		saved_cmaplen = 256;
18379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		saved_cmap=(__u16 *)SDL_malloc(3*saved_cmaplen*sizeof(*saved_cmap));
18389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( saved_cmap != NULL ) {
18399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_SavePaletteTo(this, saved_cmaplen, saved_cmap);
18409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
18419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Allocate new identity colormap */
18439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		for ( i=0; i<256; ++i ) {
18449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	      		new_entries[(0*256)+i] =
18459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			new_entries[(1*256)+i] =
18469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			new_entries[(2*256)+i] = (i<<8)|i;
18479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
18489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		FB_RestorePaletteFrom(this, 256, new_entries);
18499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
18509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
18519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_RestorePalette(_THIS)
18539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
18549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Restore the original palette */
18559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( saved_cmap ) {
18569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		FB_RestorePaletteFrom(this, saved_cmaplen, saved_cmap);
18579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_free(saved_cmap);
18589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		saved_cmap = NULL;
18599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
18609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
18619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic int FB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
18639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
18649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int i;
18659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	__u16 r[256];
18669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	__u16 g[256];
18679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	__u16 b[256];
18689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	struct fb_cmap cmap;
18699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Set up the colormap */
18719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for (i = 0; i < ncolors; i++) {
18729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		r[i] = colors[i].r << 8;
18739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		g[i] = colors[i].g << 8;
18749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		b[i] = colors[i].b << 8;
18759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
18769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.start = firstcolor;
18779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.len = ncolors;
18789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.red = r;
18799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.green = g;
18809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.blue = b;
18819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	cmap.transp = NULL;
18829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
18839682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if( (ioctl(console_fd, FBIOPUTCMAP, &cmap) < 0) ||
18849682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	    !(this->screen->flags & SDL_HWPALETTE) ) {
18859682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	        colors = this->screen->format->palette->colors;
18869682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		ncolors = this->screen->format->palette->ncolors;
18879682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		cmap.start = 0;
18889682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		cmap.len = ncolors;
18899682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_memset(r, 0, sizeof(r));
18909682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_memset(g, 0, sizeof(g));
18919682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_memset(b, 0, sizeof(b));
18929682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( ioctl(console_fd, FBIOGETCMAP, &cmap) == 0 ) {
18939682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			for ( i=ncolors-1; i>=0; --i ) {
18949682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				colors[i].r = (r[i]>>8);
18959682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				colors[i].g = (g[i]>>8);
18969682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				colors[i].b = (b[i]>>8);
18979682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
18989682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
18999682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		return(0);
19009682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
19019682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	return(1);
19029682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
19039682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19049682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall/* Note:  If we are terminated, this could be called in the middle of
19059682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall   another SDL video routine -- notably UpdateRects.
19069682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall*/
19079682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hallstatic void FB_VideoQuit(_THIS)
19089682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall{
19099682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	int i, j;
19109682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19119682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( this->screen ) {
19129682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Clear screen and tell SDL not to free the pixels */
19139682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19149682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		const char *dontClearPixels = SDL_getenv("SDL_FBCON_DONT_CLEAR");
19159682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19169682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* If the framebuffer is not to be cleared, make sure that we won't
19179682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		 * display the previous frame when disabling double buffering. */
19189682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( dontClearPixels && flip_page == 0 ) {
19199682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_memcpy(flip_address[0], flip_address[1], this->screen->pitch * this->screen->h);
19209682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
19219682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19229682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( !dontClearPixels && this->screen->pixels && FB_InGraphicsMode(this) ) {
19239682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#if defined(__powerpc__) || defined(__ia64__)	/* SIGBUS when using SDL_memset() ?? */
19249682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			Uint8 *rowp = (Uint8 *)this->screen->pixels;
19259682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			int left = this->screen->pitch*this->screen->h;
19269682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			while ( left-- ) { *rowp++ = 0; }
19279682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#else
19289682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_memset(this->screen->pixels,0,this->screen->h*this->screen->pitch);
19299682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall#endif
19309682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
19319682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* This test fails when using the VGA16 shadow memory */
19329682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( ((char *)this->screen->pixels >= mapped_mem) &&
19339682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		     ((char *)this->screen->pixels < (mapped_mem+mapped_memlen)) ) {
19349682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			this->screen->pixels = NULL;
19359682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
19369682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
19379682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19389682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Clear the lock mutex */
19399682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( hw_lock ) {
19409682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		SDL_DestroyMutex(hw_lock);
19419682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		hw_lock = NULL;
19429682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
19439682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19449682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Clean up defined video modes */
19459682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	for ( i=0; i<NUM_MODELISTS; ++i ) {
19469682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( SDL_modelist[i] != NULL ) {
19479682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			for ( j=0; SDL_modelist[i][j]; ++j ) {
19489682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall				SDL_free(SDL_modelist[i][j]);
19499682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			}
19509682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_free(SDL_modelist[i]);
19519682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			SDL_modelist[i] = NULL;
19529682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
19539682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
19549682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19559682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Clean up the memory bucket list */
19569682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_FreeHWSurfaces(this);
19579682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19589682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	/* Close console and input file descriptors */
19599682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	if ( console_fd > 0 ) {
19609682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Unmap the video framebuffer and I/O registers */
19619682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( mapped_mem ) {
19629682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			munmap(mapped_mem, mapped_memlen);
19639682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			mapped_mem = NULL;
19649682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
19659682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( mapped_io ) {
19669682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			munmap(mapped_io, mapped_iolen);
19679682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			mapped_io = NULL;
19689682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
19699682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19709682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* Restore the original video mode and palette */
19719682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		if ( FB_InGraphicsMode(this) ) {
19729682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			FB_RestorePalette(this);
19739682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall			ioctl(console_fd, FBIOPUT_VSCREENINFO, &saved_vinfo);
19749682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		}
19759682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall
19769682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		/* We're all done with the framebuffer */
19779682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		close(console_fd);
19789682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall		console_fd = -1;
19799682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	}
19809682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_CloseMouse(this);
19819682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall	FB_CloseKeyboard(this);
19829682c8870b8ff5e4ac2e4c70b759f791c6f38c1fJesse Hall}
1983