src/video/fbcon/SDL_fbvideo.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 02 Jan 2006 09:32:54 +0000
changeset 1217 ae9981987c2f
parent 1215 d082d2d66ec8
child 1312 c9b51268668f
permissions -rw-r--r--
Oops, actually use the timings in the modes db. :)
FIXME: Add some way of specifying the refresh rate we want to select!
slouken@0
     1
/*
slouken@0
     2
	SDL - Simple DirectMedia Layer
slouken@769
     3
    Copyright (C) 1997-2004 Sam Lantinga
slouken@0
     4
slouken@0
     5
	This library is free software; you can redistribute it and/or
slouken@0
     6
	modify it under the terms of the GNU Library General Public
slouken@0
     7
	License as published by the Free Software Foundation; either
slouken@0
     8
	version 2 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
	This library is distributed in the hope that it will be useful,
slouken@0
    11
	but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@0
    13
	Library General Public License for more details.
slouken@0
    14
slouken@0
    15
	You should have received a copy of the GNU Library General Public
slouken@0
    16
	License along with this library; if not, write to the Free
slouken@0
    17
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@0
    18
slouken@0
    19
	Sam Lantinga
slouken@252
    20
	slouken@libsdl.org
slouken@0
    21
*/
slouken@0
    22
slouken@0
    23
#ifdef SAVE_RCSID
slouken@0
    24
static char rcsid =
slouken@0
    25
 "@(#) $Id$";
slouken@0
    26
#endif
slouken@0
    27
slouken@0
    28
/* Framebuffer console based SDL video driver implementation.
slouken@0
    29
*/
slouken@0
    30
slouken@0
    31
#include <stdlib.h>
slouken@0
    32
#include <stdio.h>
slouken@0
    33
#include <string.h>
slouken@0
    34
#include <fcntl.h>
slouken@0
    35
#include <unistd.h>
slouken@0
    36
#include <sys/ioctl.h>
slouken@0
    37
#include <sys/mman.h>
slouken@0
    38
#include <asm/page.h>		/* For definition of PAGE_SIZE */
slouken@0
    39
slouken@0
    40
#include "SDL.h"
slouken@0
    41
#include "SDL_error.h"
slouken@0
    42
#include "SDL_video.h"
slouken@0
    43
#include "SDL_mouse.h"
slouken@0
    44
#include "SDL_sysvideo.h"
slouken@0
    45
#include "SDL_pixels_c.h"
slouken@0
    46
#include "SDL_events_c.h"
slouken@0
    47
#include "SDL_fbvideo.h"
slouken@0
    48
#include "SDL_fbmouse_c.h"
slouken@0
    49
#include "SDL_fbevents_c.h"
slouken@0
    50
#include "SDL_fb3dfx.h"
slouken@0
    51
#include "SDL_fbmatrox.h"
slouken@133
    52
#include "SDL_fbriva.h"
slouken@133
    53
slouken@1215
    54
/*#define FBCON_DEBUG*/
slouken@0
    55
slouken@0
    56
#if defined(i386) && defined(FB_TYPE_VGA_PLANES)
slouken@0
    57
#define VGA16_FBCON_SUPPORT
slouken@0
    58
#ifndef FB_AUX_VGA_PLANES_VGA4
slouken@0
    59
#define FB_AUX_VGA_PLANES_VGA4	0
slouken@0
    60
#endif
slouken@0
    61
static inline void outb (unsigned char value, unsigned short port)
slouken@0
    62
{
slouken@0
    63
  __asm__ __volatile__ ("outb %b0,%w1"::"a" (value), "Nd" (port));
slouken@0
    64
} 
slouken@0
    65
#endif /* FB_TYPE_VGA_PLANES */
slouken@0
    66
slouken@0
    67
/* A list of video resolutions that we query for (sorted largest to smallest) */
slouken@91
    68
static const SDL_Rect checkres[] = {
slouken@0
    69
	{  0, 0, 1600, 1200 },		/* 16 bpp: 0x11E, or 286 */
slouken@0
    70
	{  0, 0, 1408, 1056 },		/* 16 bpp: 0x19A, or 410 */
slouken@0
    71
	{  0, 0, 1280, 1024 },		/* 16 bpp: 0x11A, or 282 */
slouken@0
    72
	{  0, 0, 1152,  864 },		/* 16 bpp: 0x192, or 402 */
slouken@0
    73
	{  0, 0, 1024,  768 },		/* 16 bpp: 0x117, or 279 */
slouken@0
    74
	{  0, 0,  960,  720 },		/* 16 bpp: 0x18A, or 394 */
slouken@0
    75
	{  0, 0,  800,  600 },		/* 16 bpp: 0x114, or 276 */
slouken@0
    76
	{  0, 0,  768,  576 },		/* 16 bpp: 0x182, or 386 */
slouken@330
    77
	{  0, 0,  720,  576 },		/* PAL */
slouken@330
    78
	{  0, 0,  720,  480 },		/* NTSC */
slouken@0
    79
	{  0, 0,  640,  480 },		/* 16 bpp: 0x111, or 273 */
slouken@0
    80
	{  0, 0,  640,  400 },		/*  8 bpp: 0x100, or 256 */
slouken@0
    81
	{  0, 0,  512,  384 },
slouken@0
    82
	{  0, 0,  320,  240 },
slouken@0
    83
	{  0, 0,  320,  200 }
slouken@0
    84
};
slouken@91
    85
static const struct {
slouken@0
    86
	int xres;
slouken@0
    87
	int yres;
slouken@0
    88
	int pixclock;
slouken@0
    89
	int left;
slouken@0
    90
	int right;
slouken@0
    91
	int upper;
slouken@0
    92
	int lower;
slouken@0
    93
	int hslen;
slouken@0
    94
	int vslen;
slouken@0
    95
	int sync;
slouken@0
    96
	int vmode;
slouken@0
    97
} vesa_timings[] = {
slouken@0
    98
#ifdef USE_VESA_TIMINGS	/* Only tested on Matrox Millenium I */
slouken@0
    99
	{  640,  400, 39771,  48, 16, 39,  8,  96, 2, 2, 0 },	/* 70 Hz */
slouken@0
   100
	{  640,  480, 39683,  48, 16, 33, 10,  96, 2, 0, 0 },	/* 60 Hz */
slouken@0
   101
	{  768,  576, 26101, 144, 16, 28,  6, 112, 4, 0, 0 },	/* 60 Hz */
slouken@0
   102
	{  800,  600, 24038, 144, 24, 28,  8, 112, 6, 0, 0 },	/* 60 Hz */
slouken@0
   103
	{  960,  720, 17686, 144, 24, 28,  8, 112, 4, 0, 0 },	/* 60 Hz */
slouken@0
   104
	{ 1024,  768, 15386, 160, 32, 30,  4, 128, 4, 0, 0 },	/* 60 Hz */
slouken@0
   105
	{ 1152,  864, 12286, 192, 32, 30,  4, 128, 4, 0, 0 },	/* 60 Hz */
slouken@0
   106
	{ 1280, 1024,  9369, 224, 32, 32,  4, 136, 4, 0, 0 },	/* 60 Hz */
slouken@0
   107
	{ 1408, 1056,  8214, 256, 40, 32,  5, 144, 5, 0, 0 },	/* 60 Hz */
slouken@0
   108
	{ 1600, 1200,/*?*/0, 272, 48, 32,  5, 152, 5, 0, 0 },	/* 60 Hz */
slouken@0
   109
#else
slouken@0
   110
	/* You can generate these timings from your XF86Config file using
slouken@0
   111
	   the 'modeline2fb' perl script included with the fbset package.
slouken@0
   112
	   These timings were generated for Matrox Millenium I, 15" monitor.
slouken@0
   113
	*/
slouken@0
   114
	{  320,  200, 79440,  16, 16, 20,  4,  48, 1, 0, 2 },	/* 70 Hz */
slouken@0
   115
	{  320,  240, 63492,  16, 16, 16,  4,  48, 2, 0, 2 },	/* 72 Hz */
slouken@0
   116
	{  512,  384, 49603,  48, 16, 16,  1,  64, 3, 0, 0 },	/* 78 Hz */
slouken@0
   117
	{  640,  400, 31746,  96, 32, 41,  1,  64, 3, 2, 0 },	/* 85 Hz */
slouken@0
   118
	{  640,  480, 31746, 120, 16, 16,  1,  64, 3, 0, 0 },	/* 75 Hz */
slouken@0
   119
	{  768,  576, 26101, 144, 16, 28,  6, 112, 4, 0, 0 },	/* 60 Hz */
slouken@0
   120
	{  800,  600, 20000,  64, 56, 23, 37, 120, 6, 3, 0 },	/* 72 Hz */
slouken@0
   121
	{  960,  720, 17686, 144, 24, 28,  8, 112, 4, 0, 0 },	/* 60 Hz */
slouken@0
   122
	{ 1024,  768, 13333, 144, 24, 29,  3, 136, 6, 0, 0 },	/* 70 Hz */
slouken@0
   123
	{ 1152,  864, 12286, 192, 32, 30,  4, 128, 4, 0, 0 },	/* 60 Hz */
slouken@0
   124
	{ 1280, 1024,  9369, 224, 32, 32,  4, 136, 4, 0, 0 },	/* 60 Hz */
slouken@0
   125
	{ 1408, 1056,  8214, 256, 40, 32,  5, 144, 5, 0, 0 },	/* 60 Hz */
slouken@0
   126
	{ 1600, 1200,/*?*/0, 272, 48, 32,  5, 152, 5, 0, 0 },	/* 60 Hz */
slouken@0
   127
#endif
slouken@0
   128
};
slouken@0
   129
slouken@0
   130
/* Initialization/Query functions */
slouken@0
   131
static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat);
slouken@0
   132
static SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
slouken@0
   133
static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
slouken@0
   134
#ifdef VGA16_FBCON_SUPPORT
slouken@0
   135
static SDL_Surface *FB_SetVGA16Mode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
slouken@0
   136
#endif
slouken@0
   137
static int FB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
slouken@0
   138
static void FB_VideoQuit(_THIS);
slouken@0
   139
slouken@0
   140
/* Hardware surface functions */
slouken@106
   141
static int FB_InitHWSurfaces(_THIS, SDL_Surface *screen, char *base, int size);
slouken@0
   142
static void FB_FreeHWSurfaces(_THIS);
slouken@0
   143
static int FB_AllocHWSurface(_THIS, SDL_Surface *surface);
slouken@0
   144
static int FB_LockHWSurface(_THIS, SDL_Surface *surface);
slouken@0
   145
static void FB_UnlockHWSurface(_THIS, SDL_Surface *surface);
slouken@0
   146
static void FB_FreeHWSurface(_THIS, SDL_Surface *surface);
slouken@0
   147
static void FB_WaitVBL(_THIS);
slouken@106
   148
static void FB_WaitIdle(_THIS);
slouken@0
   149
static int FB_FlipHWSurface(_THIS, SDL_Surface *surface);
slouken@0
   150
slouken@0
   151
/* Internal palette functions */
slouken@0
   152
static void FB_SavePalette(_THIS, struct fb_fix_screeninfo *finfo,
slouken@0
   153
                                  struct fb_var_screeninfo *vinfo);
slouken@0
   154
static void FB_RestorePalette(_THIS);
slouken@0
   155
slouken@0
   156
/* FB driver bootstrap functions */
slouken@0
   157
slouken@0
   158
static int FB_Available(void)
slouken@0
   159
{
slouken@0
   160
	int console;
slouken@0
   161
	const char *SDL_fbdev;
slouken@0
   162
slouken@0
   163
	SDL_fbdev = getenv("SDL_FBDEV");
slouken@0
   164
	if ( SDL_fbdev == NULL ) {
slouken@0
   165
		SDL_fbdev = "/dev/fb0";
slouken@0
   166
	}
slouken@0
   167
	console = open(SDL_fbdev, O_RDWR, 0);
slouken@0
   168
	if ( console >= 0 ) {
slouken@0
   169
		close(console);
slouken@0
   170
	}
slouken@0
   171
	return(console >= 0);
slouken@0
   172
}
slouken@0
   173
slouken@0
   174
static void FB_DeleteDevice(SDL_VideoDevice *device)
slouken@0
   175
{
slouken@0
   176
	free(device->hidden);
slouken@0
   177
	free(device);
slouken@0
   178
}
slouken@0
   179
slouken@0
   180
static SDL_VideoDevice *FB_CreateDevice(int devindex)
slouken@0
   181
{
slouken@0
   182
	SDL_VideoDevice *this;
slouken@0
   183
slouken@0
   184
	/* Initialize all variables that we clean on shutdown */
slouken@0
   185
	this = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
slouken@0
   186
	if ( this ) {
slouken@0
   187
		memset(this, 0, (sizeof *this));
slouken@0
   188
		this->hidden = (struct SDL_PrivateVideoData *)
slouken@0
   189
				malloc((sizeof *this->hidden));
slouken@0
   190
	}
slouken@0
   191
	if ( (this == NULL) || (this->hidden == NULL) ) {
slouken@0
   192
		SDL_OutOfMemory();
slouken@0
   193
		if ( this ) {
slouken@0
   194
			free(this);
slouken@0
   195
		}
slouken@0
   196
		return(0);
slouken@0
   197
	}
slouken@0
   198
	memset(this->hidden, 0, (sizeof *this->hidden));
slouken@0
   199
	wait_vbl = FB_WaitVBL;
slouken@106
   200
	wait_idle = FB_WaitIdle;
slouken@0
   201
	mouse_fd = -1;
slouken@0
   202
	keyboard_fd = -1;
slouken@0
   203
slouken@0
   204
	/* Set the function pointers */
slouken@0
   205
	this->VideoInit = FB_VideoInit;
slouken@0
   206
	this->ListModes = FB_ListModes;
slouken@0
   207
	this->SetVideoMode = FB_SetVideoMode;
slouken@0
   208
	this->SetColors = FB_SetColors;
slouken@0
   209
	this->UpdateRects = NULL;
slouken@0
   210
	this->VideoQuit = FB_VideoQuit;
slouken@0
   211
	this->AllocHWSurface = FB_AllocHWSurface;
slouken@0
   212
	this->CheckHWBlit = NULL;
slouken@0
   213
	this->FillHWRect = NULL;
slouken@0
   214
	this->SetHWColorKey = NULL;
slouken@0
   215
	this->SetHWAlpha = NULL;
slouken@0
   216
	this->LockHWSurface = FB_LockHWSurface;
slouken@0
   217
	this->UnlockHWSurface = FB_UnlockHWSurface;
slouken@0
   218
	this->FlipHWSurface = FB_FlipHWSurface;
slouken@0
   219
	this->FreeHWSurface = FB_FreeHWSurface;
slouken@0
   220
	this->SetCaption = NULL;
slouken@0
   221
	this->SetIcon = NULL;
slouken@0
   222
	this->IconifyWindow = NULL;
slouken@0
   223
	this->GrabInput = NULL;
slouken@0
   224
	this->GetWMInfo = NULL;
slouken@0
   225
	this->InitOSKeymap = FB_InitOSKeymap;
slouken@0
   226
	this->PumpEvents = FB_PumpEvents;
slouken@0
   227
slouken@0
   228
	this->free = FB_DeleteDevice;
slouken@0
   229
slouken@0
   230
	return this;
slouken@0
   231
}
slouken@0
   232
slouken@0
   233
VideoBootStrap FBCON_bootstrap = {
slouken@0
   234
	"fbcon", "Linux Framebuffer Console",
slouken@0
   235
	FB_Available, FB_CreateDevice
slouken@0
   236
};
slouken@0
   237
slouken@1215
   238
#define FB_MODES_DB	"/etc/fb.modes"
slouken@1215
   239
slouken@1215
   240
static int read_fbmodes_line(FILE*f, char* line, int length)
slouken@1215
   241
{
slouken@1215
   242
	int blank;
slouken@1215
   243
	char* c;
slouken@1215
   244
	int i;
slouken@1215
   245
	
slouken@1215
   246
	blank=0;
slouken@1215
   247
	/* find a relevant line */
slouken@1215
   248
	do
slouken@1215
   249
	{
slouken@1215
   250
		if (fgets(line,length,f)<=0)
slouken@1215
   251
			return 0;
slouken@1215
   252
		c=line;
slouken@1215
   253
		while(((*c=='\t')||(*c==' '))&&(*c!=0))
slouken@1215
   254
			c++;
slouken@1215
   255
		
slouken@1215
   256
		if ((*c=='\n')||(*c=='#')||(*c==0))
slouken@1215
   257
			blank=1;
slouken@1215
   258
		else
slouken@1215
   259
			blank=0;
slouken@1215
   260
	}
slouken@1215
   261
	while(blank);
slouken@1215
   262
	/* remove whitespace at the begining of the string */
slouken@1215
   263
	i=0;
slouken@1215
   264
	do
slouken@1215
   265
	{
slouken@1215
   266
		line[i]=c[i];
slouken@1215
   267
		i++;
slouken@1215
   268
	}
slouken@1215
   269
	while(c[i]!=0);
slouken@1215
   270
	return 1;
slouken@1215
   271
}
slouken@1215
   272
slouken@1215
   273
static int read_fbmodes_mode(FILE *f, struct fb_var_screeninfo *vinfo)
slouken@1215
   274
{
slouken@1215
   275
	char line[1024];
slouken@1215
   276
	char option[256];
slouken@1215
   277
slouken@1215
   278
	/* Find a "geometry" */
slouken@1215
   279
	do {
slouken@1215
   280
		if (read_fbmodes_line(f, line, sizeof(line))==0)
slouken@1215
   281
			return 0;
slouken@1215
   282
		if (strncmp(line,"geometry",8)==0)
slouken@1215
   283
			break;
slouken@1215
   284
	}
slouken@1215
   285
	while(1);
slouken@1215
   286
slouken@1215
   287
	sscanf(line, "geometry %d %d %d %d %d", &vinfo->xres, &vinfo->yres, 
slouken@1215
   288
			&vinfo->xres_virtual, &vinfo->yres_virtual, &vinfo->bits_per_pixel);
slouken@1215
   289
	if (read_fbmodes_line(f, line, sizeof(line))==0)
slouken@1215
   290
		return 0;
slouken@1215
   291
			
slouken@1215
   292
	sscanf(line, "timings %d %d %d %d %d %d %d", &vinfo->pixclock, 
slouken@1215
   293
			&vinfo->left_margin, &vinfo->right_margin, &vinfo->upper_margin, 
slouken@1215
   294
			&vinfo->lower_margin, &vinfo->hsync_len, &vinfo->vsync_len);
slouken@1215
   295
		
slouken@1215
   296
	vinfo->sync=0;
slouken@1215
   297
	vinfo->vmode=FB_VMODE_NONINTERLACED;
slouken@1215
   298
				
slouken@1215
   299
	/* Parse misc options */
slouken@1215
   300
	do {
slouken@1215
   301
		if (read_fbmodes_line(f, line, sizeof(line))==0)
slouken@1215
   302
			return 0;
slouken@1215
   303
slouken@1215
   304
		if (strncmp(line,"hsync",5)==0) {
slouken@1215
   305
			sscanf(line,"hsync %s",option);
slouken@1215
   306
			if (strncmp(option,"high",4)==0)
slouken@1215
   307
				vinfo->sync |= FB_SYNC_HOR_HIGH_ACT;
slouken@1215
   308
		}
slouken@1215
   309
		else if (strncmp(line,"vsync",5)==0) {
slouken@1215
   310
			sscanf(line,"vsync %s",option);
slouken@1215
   311
			if (strncmp(option,"high",4)==0)
slouken@1215
   312
				vinfo->sync |= FB_SYNC_VERT_HIGH_ACT;
slouken@1215
   313
		}
slouken@1215
   314
		else if (strncmp(line,"csync",5)==0) {
slouken@1215
   315
			sscanf(line,"csync %s",option);
slouken@1215
   316
			if (strncmp(option,"high",4)==0)
slouken@1215
   317
				vinfo->sync |= FB_SYNC_COMP_HIGH_ACT;
slouken@1215
   318
		}
slouken@1215
   319
		else if (strncmp(line,"extsync",5)==0) {
slouken@1215
   320
			sscanf(line,"extsync %s",option);
slouken@1215
   321
			if (strncmp(option,"true",4)==0)
slouken@1215
   322
				vinfo->sync |= FB_SYNC_EXT;
slouken@1215
   323
		}
slouken@1215
   324
		else if (strncmp(line,"laced",5)==0) {
slouken@1215
   325
			sscanf(line,"laced %s",option);
slouken@1215
   326
			if (strncmp(option,"true",4)==0)
slouken@1215
   327
				vinfo->vmode |= FB_VMODE_INTERLACED;
slouken@1215
   328
		}
slouken@1215
   329
		else if (strncmp(line,"double",6)==0) {
slouken@1215
   330
			sscanf(line,"double %s",option);
slouken@1215
   331
			if (strncmp(option,"true",4)==0)
slouken@1215
   332
				vinfo->vmode |= FB_VMODE_DOUBLE;
slouken@1215
   333
		}
slouken@1215
   334
	}
slouken@1215
   335
	while(strncmp(line,"endmode",7)!=0);
slouken@1215
   336
slouken@1215
   337
	return 1;
slouken@1215
   338
}
slouken@1215
   339
slouken@0
   340
static int FB_CheckMode(_THIS, struct fb_var_screeninfo *vinfo,
slouken@0
   341
                        int index, unsigned int *w, unsigned int *h)
slouken@0
   342
{
slouken@0
   343
	int mode_okay;
slouken@0
   344
slouken@0
   345
	mode_okay = 0;
slouken@0
   346
	vinfo->bits_per_pixel = (index+1)*8;
slouken@0
   347
	vinfo->xres = *w;
slouken@0
   348
	vinfo->xres_virtual = *w;
slouken@0
   349
	vinfo->yres = *h;
slouken@0
   350
	vinfo->yres_virtual = *h;
slouken@0
   351
	vinfo->activate = FB_ACTIVATE_TEST;
slouken@0
   352
	if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, vinfo) == 0 ) {
slouken@0
   353
#ifdef FBCON_DEBUG
slouken@0
   354
		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);
slouken@0
   355
#endif
slouken@0
   356
		if ( (((vinfo->bits_per_pixel+7)/8)-1) == index ) {
slouken@0
   357
			*w = vinfo->xres;
slouken@0
   358
			*h = vinfo->yres;
slouken@0
   359
			mode_okay = 1;
slouken@0
   360
		}
slouken@0
   361
	}
slouken@0
   362
	return mode_okay;
slouken@0
   363
}
slouken@0
   364
slouken@1215
   365
static int FB_AddMode(_THIS, int index, unsigned int w, unsigned int h, int check_timings)
slouken@0
   366
{
slouken@0
   367
	SDL_Rect *mode;
slouken@0
   368
	int i;
slouken@0
   369
	int next_mode;
slouken@0
   370
slouken@0
   371
	/* Check to see if we already have this mode */
slouken@0
   372
	if ( SDL_nummodes[index] > 0 ) {
slouken@0
   373
		mode = SDL_modelist[index][SDL_nummodes[index]-1];
slouken@0
   374
		if ( (mode->w == w) && (mode->h == h) ) {
slouken@0
   375
#ifdef FBCON_DEBUG
slouken@0
   376
			fprintf(stderr, "We already have mode %dx%d at %d bytes per pixel\n", w, h, index+1);
slouken@0
   377
#endif
slouken@0
   378
			return(0);
slouken@0
   379
		}
slouken@0
   380
	}
slouken@0
   381
slouken@0
   382
	/* Only allow a mode if we have a valid timing for it */
slouken@1215
   383
	if ( check_timings ) {
slouken@1215
   384
		int found_timing = 0;
slouken@1215
   385
		for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) {
slouken@1215
   386
			if ( (w == vesa_timings[i].xres) &&
slouken@1215
   387
			     (h == vesa_timings[i].yres) && vesa_timings[i].pixclock ) {
slouken@1215
   388
				found_timing = 1;
slouken@1215
   389
				break;
slouken@1215
   390
			}
slouken@0
   391
		}
slouken@1215
   392
		if ( !found_timing ) {
slouken@0
   393
#ifdef FBCON_DEBUG
slouken@1215
   394
			fprintf(stderr, "No valid timing line for mode %dx%d\n", w, h);
slouken@0
   395
#endif
slouken@1215
   396
			return(0);
slouken@1215
   397
		}
slouken@0
   398
	}
slouken@0
   399
slouken@0
   400
	/* Set up the new video mode rectangle */
slouken@0
   401
	mode = (SDL_Rect *)malloc(sizeof *mode);
slouken@0
   402
	if ( mode == NULL ) {
slouken@0
   403
		SDL_OutOfMemory();
slouken@0
   404
		return(-1);
slouken@0
   405
	}
slouken@0
   406
	mode->x = 0;
slouken@0
   407
	mode->y = 0;
slouken@0
   408
	mode->w = w;
slouken@0
   409
	mode->h = h;
slouken@0
   410
#ifdef FBCON_DEBUG
slouken@0
   411
	fprintf(stderr, "Adding mode %dx%d at %d bytes per pixel\n", w, h, index+1);
slouken@0
   412
#endif
slouken@0
   413
slouken@0
   414
	/* Allocate the new list of modes, and fill in the new mode */
slouken@0
   415
	next_mode = SDL_nummodes[index];
slouken@0
   416
	SDL_modelist[index] = (SDL_Rect **)
slouken@0
   417
	       realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
slouken@0
   418
	if ( SDL_modelist[index] == NULL ) {
slouken@0
   419
		SDL_OutOfMemory();
slouken@0
   420
		SDL_nummodes[index] = 0;
slouken@0
   421
		free(mode);
slouken@0
   422
		return(-1);
slouken@0
   423
	}
slouken@0
   424
	SDL_modelist[index][next_mode] = mode;
slouken@0
   425
	SDL_modelist[index][next_mode+1] = NULL;
slouken@0
   426
	SDL_nummodes[index]++;
slouken@0
   427
slouken@0
   428
	return(0);
slouken@0
   429
}
slouken@0
   430
slouken@1215
   431
static int cmpmodes(const void *va, const void *vb)
slouken@1215
   432
{
slouken@1215
   433
    const SDL_Rect *a = *(const SDL_Rect**)va;
slouken@1215
   434
    const SDL_Rect *b = *(const SDL_Rect**)vb;
slouken@1215
   435
    if ( a->h == b->h )
slouken@1215
   436
        return b->w - a->w;
slouken@1215
   437
    else
slouken@1215
   438
        return b->h - a->h;
slouken@1215
   439
}
slouken@1215
   440
slouken@1215
   441
static int FB_SortModes(_THIS)
slouken@1215
   442
{
slouken@1215
   443
	int i;
slouken@1215
   444
	for ( i=0; i<NUM_MODELISTS; ++i ) {
slouken@1215
   445
		if ( SDL_nummodes[i] > 0 ) {
slouken@1215
   446
			qsort(SDL_modelist[i], SDL_nummodes[i], sizeof *SDL_modelist[i], cmpmodes);
slouken@1215
   447
		}
slouken@1215
   448
	}
slouken@1215
   449
}
slouken@1215
   450
slouken@0
   451
static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat)
slouken@0
   452
{
slouken@0
   453
	struct fb_fix_screeninfo finfo;
slouken@0
   454
	struct fb_var_screeninfo vinfo;
slouken@0
   455
	int i, j;
slouken@0
   456
	int current_index;
slouken@0
   457
	unsigned int current_w;
slouken@0
   458
	unsigned int current_h;
slouken@0
   459
	const char *SDL_fbdev;
slouken@1215
   460
	FILE *modesdb;
slouken@0
   461
slouken@0
   462
	/* Initialize the library */
slouken@0
   463
	SDL_fbdev = getenv("SDL_FBDEV");
slouken@0
   464
	if ( SDL_fbdev == NULL ) {
slouken@0
   465
		SDL_fbdev = "/dev/fb0";
slouken@0
   466
	}
slouken@0
   467
	console_fd = open(SDL_fbdev, O_RDWR, 0);
slouken@0
   468
	if ( console_fd < 0 ) {
slouken@0
   469
		SDL_SetError("Unable to open %s", SDL_fbdev);
slouken@0
   470
		return(-1);
slouken@0
   471
	}
slouken@0
   472
slouken@0
   473
#ifndef DISABLE_THREADS
slouken@0
   474
	/* Create the hardware surface lock mutex */
slouken@0
   475
	hw_lock = SDL_CreateMutex();
slouken@0
   476
	if ( hw_lock == NULL ) {
slouken@0
   477
		SDL_SetError("Unable to create lock mutex");
slouken@0
   478
		FB_VideoQuit(this);
slouken@0
   479
		return(-1);
slouken@0
   480
	}
slouken@0
   481
#endif
slouken@0
   482
slouken@0
   483
	/* Get the type of video hardware */
slouken@0
   484
	if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
slouken@0
   485
		SDL_SetError("Couldn't get console hardware info");
slouken@0
   486
		FB_VideoQuit(this);
slouken@0
   487
		return(-1);
slouken@0
   488
	}
slouken@0
   489
	switch (finfo.type) {
slouken@0
   490
		case FB_TYPE_PACKED_PIXELS:
slouken@0
   491
			/* Supported, no worries.. */
slouken@0
   492
			break;
slouken@0
   493
#ifdef VGA16_FBCON_SUPPORT
slouken@0
   494
		case FB_TYPE_VGA_PLANES:
slouken@0
   495
			/* VGA16 is supported, but that's it */
slouken@0
   496
			if ( finfo.type_aux == FB_AUX_VGA_PLANES_VGA4 ) {
slouken@0
   497
				if ( ioperm(0x3b4, 0x3df - 0x3b4 + 1, 1) < 0 ) {
slouken@0
   498
					SDL_SetError("No I/O port permissions");
slouken@0
   499
					FB_VideoQuit(this);
slouken@0
   500
					return(-1);
slouken@0
   501
				}
slouken@0
   502
				this->SetVideoMode = FB_SetVGA16Mode;
slouken@0
   503
				break;
slouken@0
   504
			}
slouken@0
   505
			/* Fall through to unsupported case */
slouken@0
   506
#endif /* VGA16_FBCON_SUPPORT */
slouken@0
   507
		default:
slouken@0
   508
			SDL_SetError("Unsupported console hardware");
slouken@0
   509
			FB_VideoQuit(this);
slouken@0
   510
			return(-1);
slouken@0
   511
	}
slouken@0
   512
	switch (finfo.visual) {
slouken@0
   513
		case FB_VISUAL_TRUECOLOR:
slouken@0
   514
		case FB_VISUAL_PSEUDOCOLOR:
slouken@0
   515
		case FB_VISUAL_STATIC_PSEUDOCOLOR:
slouken@0
   516
		case FB_VISUAL_DIRECTCOLOR:
slouken@0
   517
			break;
slouken@0
   518
		default:
slouken@0
   519
			SDL_SetError("Unsupported console hardware");
slouken@0
   520
			FB_VideoQuit(this);
slouken@0
   521
			return(-1);
slouken@0
   522
	}
slouken@0
   523
slouken@0
   524
	/* Check if the user wants to disable hardware acceleration */
slouken@0
   525
	{ const char *fb_accel;
slouken@0
   526
		fb_accel = getenv("SDL_FBACCEL");
slouken@0
   527
		if ( fb_accel ) {
slouken@0
   528
			finfo.accel = atoi(fb_accel);
slouken@0
   529
		}
slouken@0
   530
	}
slouken@0
   531
slouken@0
   532
	/* Memory map the device, compensating for buggy PPC mmap() */
slouken@0
   533
	mapped_offset = (((long)finfo.smem_start) -
slouken@0
   534
	                (((long)finfo.smem_start)&~(PAGE_SIZE-1)));
slouken@0
   535
	mapped_memlen = finfo.smem_len+mapped_offset;
slouken@0
   536
	mapped_mem = mmap(NULL, mapped_memlen,
slouken@0
   537
	                  PROT_READ|PROT_WRITE, MAP_SHARED, console_fd, 0);
slouken@0
   538
	if ( mapped_mem == (char *)-1 ) {
slouken@0
   539
		SDL_SetError("Unable to memory map the video hardware");
slouken@0
   540
		mapped_mem = NULL;
slouken@0
   541
		FB_VideoQuit(this);
slouken@0
   542
		return(-1);
slouken@0
   543
	}
slouken@0
   544
slouken@0
   545
	/* Determine the current screen depth */
slouken@0
   546
	if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
slouken@0
   547
		SDL_SetError("Couldn't get console pixel format");
slouken@0
   548
		FB_VideoQuit(this);
slouken@0
   549
		return(-1);
slouken@0
   550
	}
slouken@0
   551
	vformat->BitsPerPixel = vinfo.bits_per_pixel;
slouken@0
   552
	if ( vformat->BitsPerPixel < 8 ) {
slouken@0
   553
		/* Assuming VGA16, we handle this via a shadow framebuffer */
slouken@0
   554
		vformat->BitsPerPixel = 8;
slouken@0
   555
	}
slouken@0
   556
	for ( i=0; i<vinfo.red.length; ++i ) {
slouken@0
   557
		vformat->Rmask <<= 1;
slouken@0
   558
		vformat->Rmask |= (0x00000001<<vinfo.red.offset);
slouken@0
   559
	}
slouken@0
   560
	for ( i=0; i<vinfo.green.length; ++i ) {
slouken@0
   561
		vformat->Gmask <<= 1;
slouken@0
   562
		vformat->Gmask |= (0x00000001<<vinfo.green.offset);
slouken@0
   563
	}
slouken@0
   564
	for ( i=0; i<vinfo.blue.length; ++i ) {
slouken@0
   565
		vformat->Bmask <<= 1;
slouken@0
   566
		vformat->Bmask |= (0x00000001<<vinfo.blue.offset);
slouken@0
   567
	}
slouken@0
   568
	saved_vinfo = vinfo;
slouken@0
   569
slouken@0
   570
	/* Save hardware palette, if needed */
slouken@0
   571
	FB_SavePalette(this, &finfo, &vinfo);
slouken@0
   572
slouken@0
   573
	/* If the I/O registers are available, memory map them so we
slouken@0
   574
	   can take advantage of any supported hardware acceleration.
slouken@0
   575
	 */
slouken@0
   576
	vinfo.accel_flags = 0;	/* Temporarily reserve registers */
slouken@0
   577
	ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo);
slouken@0
   578
	if ( finfo.accel && finfo.mmio_len ) {
slouken@0
   579
		mapped_iolen = finfo.mmio_len;
slouken@0
   580
		mapped_io = mmap(NULL, mapped_iolen, PROT_READ|PROT_WRITE,
slouken@0
   581
		                 MAP_SHARED, console_fd, mapped_memlen);
slouken@0
   582
		if ( mapped_io == (char *)-1 ) {
slouken@0
   583
			/* Hmm, failed to memory map I/O registers */
slouken@0
   584
			mapped_io = NULL;
slouken@0
   585
		}
slouken@0
   586
	}
slouken@0
   587
slouken@0
   588
	/* Query for the list of available video modes */
slouken@0
   589
	current_w = vinfo.xres;
slouken@0
   590
	current_h = vinfo.yres;
slouken@0
   591
	current_index = ((vinfo.bits_per_pixel+7)/8)-1;
slouken@1215
   592
	modesdb = fopen(FB_MODES_DB, "r");
slouken@1215
   593
	for ( i=0; i<NUM_MODELISTS; ++i ) {
slouken@1215
   594
		SDL_nummodes[i] = 0;
slouken@1215
   595
		SDL_modelist[i] = NULL;
slouken@1215
   596
	}
slouken@941
   597
	if ( getenv("SDL_FB_BROKEN_MODES") != NULL ) {
slouken@1215
   598
		FB_AddMode(this, current_index, current_w, current_h, 0);
slouken@1215
   599
	} else if(modesdb) {
slouken@1215
   600
		while ( read_fbmodes_mode(modesdb, &vinfo) ) {
slouken@1215
   601
			for ( i=0; i<NUM_MODELISTS; ++i ) {
slouken@1215
   602
				unsigned int w, h;
slouken@1215
   603
slouken@1215
   604
				/* See if we are querying for the current mode */
slouken@1215
   605
				w = vinfo.xres;
slouken@1215
   606
				h = vinfo.yres;
slouken@1215
   607
				if ( i == current_index ) {
slouken@1215
   608
					if ( (current_w > w) || (current_h > h) ) {
slouken@1215
   609
						/* Only check once */
slouken@1215
   610
						FB_AddMode(this, i, current_w, current_h, 0);
slouken@1215
   611
						current_index = -1;
slouken@1215
   612
					}
slouken@1215
   613
				}
slouken@1215
   614
				if ( FB_CheckMode(this, &vinfo, i, &w, &h) ) {
slouken@1215
   615
					FB_AddMode(this, i, w, h, 0);
slouken@1215
   616
				}
slouken@1215
   617
			}
slouken@1215
   618
		}
slouken@1215
   619
		fclose(modesdb);
slouken@1215
   620
		FB_SortModes(this);
slouken@941
   621
	} else {
slouken@941
   622
		for ( i=0; i<NUM_MODELISTS; ++i ) {
slouken@941
   623
			for ( j=0; j<(sizeof(checkres)/sizeof(checkres[0])); ++j ) {
slouken@941
   624
				unsigned int w, h;
slouken@0
   625
slouken@941
   626
				/* See if we are querying for the current mode */
slouken@941
   627
				w = checkres[j].w;
slouken@941
   628
				h = checkres[j].h;
slouken@941
   629
				if ( i == current_index ) {
slouken@941
   630
					if ( (current_w > w) || (current_h > h) ) {
slouken@941
   631
						/* Only check once */
slouken@1215
   632
						FB_AddMode(this, i, current_w, current_h, 0);
slouken@941
   633
						current_index = -1;
slouken@941
   634
					}
slouken@0
   635
				}
slouken@941
   636
				if ( FB_CheckMode(this, &vinfo, i, &w, &h) ) {
slouken@1215
   637
					FB_AddMode(this, i, w, h, 1);
slouken@941
   638
				}
slouken@0
   639
			}
slouken@0
   640
		}
slouken@0
   641
	}
slouken@0
   642
slouken@0
   643
	/* Fill in our hardware acceleration capabilities */
slouken@0
   644
	this->info.wm_available = 0;
slouken@0
   645
	this->info.hw_available = 1;
slouken@0
   646
	this->info.video_mem = finfo.smem_len/1024;
slouken@0
   647
	if ( mapped_io ) {
slouken@0
   648
		switch (finfo.accel) {
slouken@0
   649
		    case FB_ACCEL_MATROX_MGA2064W:
slouken@0
   650
		    case FB_ACCEL_MATROX_MGA1064SG:
slouken@0
   651
		    case FB_ACCEL_MATROX_MGA2164W:
slouken@0
   652
		    case FB_ACCEL_MATROX_MGA2164W_AGP:
slouken@0
   653
		    case FB_ACCEL_MATROX_MGAG100:
slouken@0
   654
		    /*case FB_ACCEL_MATROX_MGAG200: G200 acceleration broken! */
slouken@0
   655
		    case FB_ACCEL_MATROX_MGAG400:
slouken@0
   656
#ifdef FBACCEL_DEBUG
slouken@0
   657
			printf("Matrox hardware accelerator!\n");
slouken@0
   658
#endif
slouken@0
   659
			FB_MatroxAccel(this, finfo.accel);
slouken@0
   660
			break;
slouken@0
   661
		    case FB_ACCEL_3DFX_BANSHEE:
slouken@0
   662
#ifdef FBACCEL_DEBUG
slouken@0
   663
			printf("3DFX hardware accelerator!\n");
slouken@0
   664
#endif
slouken@0
   665
			FB_3DfxAccel(this, finfo.accel);
slouken@0
   666
			break;
slouken@133
   667
		    case FB_ACCEL_NV3:
slouken@133
   668
		    case FB_ACCEL_NV4:
slouken@133
   669
#ifdef FBACCEL_DEBUG
slouken@133
   670
			printf("NVidia hardware accelerator!\n");
slouken@133
   671
#endif
slouken@133
   672
			FB_RivaAccel(this, finfo.accel);
slouken@133
   673
			break;
slouken@0
   674
		    default:
slouken@0
   675
#ifdef FBACCEL_DEBUG
slouken@0
   676
			printf("Unknown hardware accelerator.\n");
slouken@0
   677
#endif
slouken@0
   678
			break;
slouken@0
   679
		}
slouken@0
   680
	}
slouken@0
   681
slouken@0
   682
	/* Enable mouse and keyboard support */
slouken@0
   683
	if ( FB_OpenKeyboard(this) < 0 ) {
slouken@0
   684
		FB_VideoQuit(this);
slouken@0
   685
		return(-1);
slouken@0
   686
	}
slouken@0
   687
	if ( FB_OpenMouse(this) < 0 ) {
slouken@0
   688
		const char *sdl_nomouse;
slouken@0
   689
slouken@0
   690
		sdl_nomouse = getenv("SDL_NOMOUSE");
slouken@0
   691
		if ( ! sdl_nomouse ) {
slouken@0
   692
			SDL_SetError("Unable to open mouse");
slouken@0
   693
			FB_VideoQuit(this);
slouken@0
   694
			return(-1);
slouken@0
   695
		}
slouken@0
   696
	}
slouken@0
   697
slouken@0
   698
	/* We're done! */
slouken@0
   699
	return(0);
slouken@0
   700
}
slouken@0
   701
slouken@0
   702
static SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
slouken@0
   703
{
slouken@0
   704
	return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
slouken@0
   705
}
slouken@0
   706
slouken@0
   707
/* Various screen update functions available */
slouken@0
   708
static void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
slouken@0
   709
#ifdef VGA16_FBCON_SUPPORT
slouken@0
   710
static void FB_VGA16Update(_THIS, int numrects, SDL_Rect *rects);
slouken@0
   711
#endif
slouken@0
   712
slouken@0
   713
#ifdef FBCON_DEBUG
slouken@0
   714
static void print_vinfo(struct fb_var_screeninfo *vinfo)
slouken@0
   715
{
slouken@0
   716
	fprintf(stderr, "Printing vinfo:\n");
slouken@0
   717
	fprintf(stderr, "\txres: %d\n", vinfo->xres);
slouken@0
   718
	fprintf(stderr, "\tyres: %d\n", vinfo->yres);
slouken@0
   719
	fprintf(stderr, "\txres_virtual: %d\n", vinfo->xres_virtual);
slouken@0
   720
	fprintf(stderr, "\tyres_virtual: %d\n", vinfo->yres_virtual);
slouken@0
   721
	fprintf(stderr, "\txoffset: %d\n", vinfo->xoffset);
slouken@0
   722
	fprintf(stderr, "\tyoffset: %d\n", vinfo->yoffset);
slouken@0
   723
	fprintf(stderr, "\tbits_per_pixel: %d\n", vinfo->bits_per_pixel);
slouken@0
   724
	fprintf(stderr, "\tgrayscale: %d\n", vinfo->grayscale);
slouken@0
   725
	fprintf(stderr, "\tnonstd: %d\n", vinfo->nonstd);
slouken@0
   726
	fprintf(stderr, "\tactivate: %d\n", vinfo->activate);
slouken@0
   727
	fprintf(stderr, "\theight: %d\n", vinfo->height);
slouken@0
   728
	fprintf(stderr, "\twidth: %d\n", vinfo->width);
slouken@0
   729
	fprintf(stderr, "\taccel_flags: %d\n", vinfo->accel_flags);
slouken@0
   730
	fprintf(stderr, "\tpixclock: %d\n", vinfo->pixclock);
slouken@0
   731
	fprintf(stderr, "\tleft_margin: %d\n", vinfo->left_margin);
slouken@0
   732
	fprintf(stderr, "\tright_margin: %d\n", vinfo->right_margin);
slouken@0
   733
	fprintf(stderr, "\tupper_margin: %d\n", vinfo->upper_margin);
slouken@0
   734
	fprintf(stderr, "\tlower_margin: %d\n", vinfo->lower_margin);
slouken@0
   735
	fprintf(stderr, "\thsync_len: %d\n", vinfo->hsync_len);
slouken@0
   736
	fprintf(stderr, "\tvsync_len: %d\n", vinfo->vsync_len);
slouken@0
   737
	fprintf(stderr, "\tsync: %d\n", vinfo->sync);
slouken@0
   738
	fprintf(stderr, "\tvmode: %d\n", vinfo->vmode);
slouken@0
   739
	fprintf(stderr, "\tred: %d/%d\n", vinfo->red.length, vinfo->red.offset);
slouken@0
   740
	fprintf(stderr, "\tgreen: %d/%d\n", vinfo->green.length, vinfo->green.offset);
slouken@0
   741
	fprintf(stderr, "\tblue: %d/%d\n", vinfo->blue.length, vinfo->blue.offset);
slouken@0
   742
	fprintf(stderr, "\talpha: %d/%d\n", vinfo->transp.length, vinfo->transp.offset);
slouken@0
   743
}
slouken@0
   744
static void print_finfo(struct fb_fix_screeninfo *finfo)
slouken@0
   745
{
slouken@0
   746
	fprintf(stderr, "Printing finfo:\n");
slouken@0
   747
	fprintf(stderr, "\tsmem_start = %p\n", (char *)finfo->smem_start);
slouken@0
   748
	fprintf(stderr, "\tsmem_len = %d\n", finfo->smem_len);
slouken@0
   749
	fprintf(stderr, "\ttype = %d\n", finfo->type);
slouken@0
   750
	fprintf(stderr, "\ttype_aux = %d\n", finfo->type_aux);
slouken@0
   751
	fprintf(stderr, "\tvisual = %d\n", finfo->visual);
slouken@0
   752
	fprintf(stderr, "\txpanstep = %d\n", finfo->xpanstep);
slouken@0
   753
	fprintf(stderr, "\typanstep = %d\n", finfo->ypanstep);
slouken@0
   754
	fprintf(stderr, "\tywrapstep = %d\n", finfo->ywrapstep);
slouken@0
   755
	fprintf(stderr, "\tline_length = %d\n", finfo->line_length);
slouken@0
   756
	fprintf(stderr, "\tmmio_start = %p\n", (char *)finfo->mmio_start);
slouken@0
   757
	fprintf(stderr, "\tmmio_len = %d\n", finfo->mmio_len);
slouken@0
   758
	fprintf(stderr, "\taccel = %d\n", finfo->accel);
slouken@0
   759
}
slouken@0
   760
#endif
slouken@0
   761
slouken@0
   762
static int choose_fbmodes_mode(struct fb_var_screeninfo *vinfo)
slouken@0
   763
{
slouken@0
   764
	int matched;
slouken@1215
   765
	FILE *modesdb;
slouken@1215
   766
	struct fb_var_screeninfo cinfo;
slouken@0
   767
slouken@0
   768
	matched = 0;
slouken@1215
   769
	modesdb = fopen(FB_MODES_DB, "r");
slouken@1215
   770
	if ( modesdb ) {
slouken@1215
   771
		/* Parse the mode definition file */
slouken@1215
   772
		while ( read_fbmodes_mode(modesdb, &cinfo) ) {
slouken@1217
   773
			if ( (vinfo->xres == cinfo.xres && vinfo->yres == cinfo.yres) &&
slouken@1217
   774
			     (!matched || (vinfo->bits_per_pixel == cinfo.bits_per_pixel)) ) {
slouken@1217
   775
				vinfo->pixclock = cinfo.pixclock;
slouken@1217
   776
				vinfo->left_margin = cinfo.left_margin;
slouken@1217
   777
				vinfo->right_margin = cinfo.right_margin;
slouken@1217
   778
				vinfo->upper_margin = cinfo.upper_margin;
slouken@1217
   779
				vinfo->lower_margin = cinfo.lower_margin;
slouken@1217
   780
				vinfo->hsync_len = cinfo.hsync_len;
slouken@1217
   781
				vinfo->vsync_len = cinfo.vsync_len;
slouken@1217
   782
				if ( matched ) {
slouken@1217
   783
					break;
slouken@1217
   784
				}
slouken@1215
   785
				matched = 1;
slouken@1215
   786
			}
slouken@1215
   787
		}
slouken@1215
   788
		fclose(modesdb);
slouken@0
   789
	}
slouken@0
   790
	return(matched);
slouken@0
   791
}
slouken@0
   792
slouken@0
   793
static int choose_vesa_mode(struct fb_var_screeninfo *vinfo)
slouken@0
   794
{
slouken@0
   795
	int matched;
slouken@0
   796
	int i;
slouken@0
   797
slouken@0
   798
	/* Check for VESA timings */
slouken@0
   799
	matched = 0;
slouken@0
   800
	for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) {
slouken@0
   801
		if ( (vinfo->xres == vesa_timings[i].xres) &&
slouken@0
   802
		     (vinfo->yres == vesa_timings[i].yres) ) {
slouken@0
   803
#ifdef FBCON_DEBUG
slouken@0
   804
			fprintf(stderr, "Using VESA timings for %dx%d\n",
slouken@0
   805
						vinfo->xres, vinfo->yres);
slouken@0
   806
#endif
slouken@0
   807
			if ( vesa_timings[i].pixclock ) {
slouken@0
   808
				vinfo->pixclock = vesa_timings[i].pixclock;
slouken@0
   809
			}
slouken@0
   810
			vinfo->left_margin = vesa_timings[i].left;
slouken@0
   811
			vinfo->right_margin = vesa_timings[i].right;
slouken@0
   812
			vinfo->upper_margin = vesa_timings[i].upper;
slouken@0
   813
			vinfo->lower_margin = vesa_timings[i].lower;
slouken@0
   814
			vinfo->hsync_len = vesa_timings[i].hslen;
slouken@0
   815
			vinfo->vsync_len = vesa_timings[i].vslen;
slouken@0
   816
			vinfo->sync = vesa_timings[i].sync;
slouken@0
   817
			vinfo->vmode = vesa_timings[i].vmode;
slouken@0
   818
			matched = 1;
slouken@0
   819
			break;
slouken@0
   820
		}
slouken@0
   821
	}
slouken@0
   822
	return(matched);
slouken@0
   823
}
slouken@0
   824
slouken@0
   825
#ifdef VGA16_FBCON_SUPPORT
slouken@0
   826
static SDL_Surface *FB_SetVGA16Mode(_THIS, SDL_Surface *current,
slouken@0
   827
				int width, int height, int bpp, Uint32 flags)
slouken@0
   828
{
slouken@0
   829
	struct fb_fix_screeninfo finfo;
slouken@0
   830
	struct fb_var_screeninfo vinfo;
slouken@0
   831
slouken@0
   832
	/* Set the terminal into graphics mode */
slouken@0
   833
	if ( FB_EnterGraphicsMode(this) < 0 ) {
slouken@0
   834
		return(NULL);
slouken@0
   835
	}
slouken@0
   836
slouken@0
   837
	/* Restore the original palette */
slouken@0
   838
	FB_RestorePalette(this);
slouken@0
   839
slouken@0
   840
	/* Set the video mode and get the final screen format */
slouken@0
   841
	if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
slouken@0
   842
		SDL_SetError("Couldn't get console screen info");
slouken@0
   843
		return(NULL);
slouken@0
   844
	}
slouken@0
   845
	cache_vinfo = vinfo;
slouken@0
   846
#ifdef FBCON_DEBUG
slouken@0
   847
	fprintf(stderr, "Printing actual vinfo:\n");
slouken@0
   848
	print_vinfo(&vinfo);
slouken@0
   849
#endif
slouken@0
   850
	if ( ! SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) {
slouken@0
   851
		return(NULL);
slouken@0
   852
	}
slouken@106
   853
	current->format->palette->ncolors = 16;
slouken@0
   854
slouken@0
   855
	/* Get the fixed information about the console hardware.
slouken@0
   856
	   This is necessary since finfo.line_length changes.
slouken@0
   857
	 */
slouken@0
   858
	if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
slouken@0
   859
		SDL_SetError("Couldn't get console hardware info");
slouken@0
   860
		return(NULL);
slouken@0
   861
	}
slouken@0
   862
#ifdef FBCON_DEBUG
slouken@0
   863
	fprintf(stderr, "Printing actual finfo:\n");
slouken@0
   864
	print_finfo(&finfo);
slouken@0
   865
#endif
slouken@0
   866
slouken@0
   867
	/* Save hardware palette, if needed */
slouken@0
   868
	FB_SavePalette(this, &finfo, &vinfo);
slouken@0
   869
slouken@0
   870
	/* Set up the new mode framebuffer */
slouken@0
   871
	current->flags = SDL_FULLSCREEN;
slouken@0
   872
	current->w = vinfo.xres;
slouken@0
   873
	current->h = vinfo.yres;
slouken@0
   874
	current->pitch = current->w;
slouken@0
   875
	current->pixels = malloc(current->h*current->pitch);
slouken@0
   876
slouken@0
   877
	/* Set the update rectangle function */
slouken@0
   878
	this->UpdateRects = FB_VGA16Update;
slouken@0
   879
slouken@0
   880
	/* We're done */
slouken@0
   881
	return(current);
slouken@0
   882
}
slouken@0
   883
#endif /* VGA16_FBCON_SUPPORT */
slouken@0
   884
slouken@0
   885
static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current,
slouken@0
   886
				int width, int height, int bpp, Uint32 flags)
slouken@0
   887
{
slouken@0
   888
	struct fb_fix_screeninfo finfo;
slouken@0
   889
	struct fb_var_screeninfo vinfo;
slouken@0
   890
	int i;
slouken@0
   891
	Uint32 Rmask;
slouken@0
   892
	Uint32 Gmask;
slouken@0
   893
	Uint32 Bmask;
slouken@0
   894
	char *surfaces_mem;
slouken@0
   895
	int surfaces_len;
slouken@0
   896
slouken@0
   897
	/* Set the terminal into graphics mode */
slouken@0
   898
	if ( FB_EnterGraphicsMode(this) < 0 ) {
slouken@0
   899
		return(NULL);
slouken@0
   900
	}
slouken@0
   901
slouken@0
   902
	/* Restore the original palette */
slouken@0
   903
	FB_RestorePalette(this);
slouken@0
   904
slouken@0
   905
	/* Set the video mode and get the final screen format */
slouken@0
   906
	if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
slouken@0
   907
		SDL_SetError("Couldn't get console screen info");
slouken@0
   908
		return(NULL);
slouken@0
   909
	}
slouken@0
   910
#ifdef FBCON_DEBUG
slouken@0
   911
	fprintf(stderr, "Printing original vinfo:\n");
slouken@0
   912
	print_vinfo(&vinfo);
slouken@0
   913
#endif
slouken@0
   914
	if ( (vinfo.xres != width) || (vinfo.yres != height) ||
slouken@0
   915
	     (vinfo.bits_per_pixel != bpp) || (flags & SDL_DOUBLEBUF) ) {
slouken@0
   916
		vinfo.activate = FB_ACTIVATE_NOW;
slouken@0
   917
		vinfo.accel_flags = 0;
slouken@0
   918
		vinfo.bits_per_pixel = bpp;
slouken@0
   919
		vinfo.xres = width;
slouken@0
   920
		vinfo.xres_virtual = width;
slouken@0
   921
		vinfo.yres = height;
slouken@0
   922
		if ( flags & SDL_DOUBLEBUF ) {
slouken@0
   923
			vinfo.yres_virtual = height*2;
slouken@0
   924
		} else {
slouken@0
   925
			vinfo.yres_virtual = height;
slouken@0
   926
		}
slouken@0
   927
		vinfo.xoffset = 0;
slouken@0
   928
		vinfo.yoffset = 0;
slouken@0
   929
		vinfo.red.length = vinfo.red.offset = 0;
slouken@0
   930
		vinfo.green.length = vinfo.green.offset = 0;
slouken@0
   931
		vinfo.blue.length = vinfo.blue.offset = 0;
slouken@0
   932
		vinfo.transp.length = vinfo.transp.offset = 0;
slouken@0
   933
		if ( ! choose_fbmodes_mode(&vinfo) ) {
slouken@0
   934
			choose_vesa_mode(&vinfo);
slouken@0
   935
		}
slouken@0
   936
#ifdef FBCON_DEBUG
slouken@0
   937
		fprintf(stderr, "Printing wanted vinfo:\n");
slouken@0
   938
		print_vinfo(&vinfo);
slouken@0
   939
#endif
slouken@0
   940
		if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {
slouken@0
   941
			vinfo.yres_virtual = height;
slouken@0
   942
			if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {
slouken@0
   943
				SDL_SetError("Couldn't set console screen info");
slouken@0
   944
				return(NULL);
slouken@0
   945
			}
slouken@0
   946
		}
slouken@106
   947
	} else {
slouken@106
   948
		int maxheight;
slouken@106
   949
slouken@106
   950
		/* Figure out how much video memory is available */
slouken@106
   951
		if ( flags & SDL_DOUBLEBUF ) {
slouken@106
   952
			maxheight = height*2;
slouken@106
   953
		} else {
slouken@106
   954
			maxheight = height;
slouken@106
   955
		}
slouken@106
   956
		if ( vinfo.yres_virtual > maxheight ) {
slouken@106
   957
			vinfo.yres_virtual = maxheight;
slouken@106
   958
		}
slouken@0
   959
	}
slouken@0
   960
	cache_vinfo = vinfo;
slouken@0
   961
#ifdef FBCON_DEBUG
slouken@0
   962
	fprintf(stderr, "Printing actual vinfo:\n");
slouken@0
   963
	print_vinfo(&vinfo);
slouken@0
   964
#endif
slouken@0
   965
	Rmask = 0;
slouken@0
   966
	for ( i=0; i<vinfo.red.length; ++i ) {
slouken@0
   967
		Rmask <<= 1;
slouken@0
   968
		Rmask |= (0x00000001<<vinfo.red.offset);
slouken@0
   969
	}
slouken@0
   970
	Gmask = 0;
slouken@0
   971
	for ( i=0; i<vinfo.green.length; ++i ) {
slouken@0
   972
		Gmask <<= 1;
slouken@0
   973
		Gmask |= (0x00000001<<vinfo.green.offset);
slouken@0
   974
	}
slouken@0
   975
	Bmask = 0;
slouken@0
   976
	for ( i=0; i<vinfo.blue.length; ++i ) {
slouken@0
   977
		Bmask <<= 1;
slouken@0
   978
		Bmask |= (0x00000001<<vinfo.blue.offset);
slouken@0
   979
	}
slouken@0
   980
	if ( ! SDL_ReallocFormat(current, vinfo.bits_per_pixel,
slouken@0
   981
	                                  Rmask, Gmask, Bmask, 0) ) {
slouken@0
   982
		return(NULL);
slouken@0
   983
	}
slouken@0
   984
slouken@0
   985
	/* Get the fixed information about the console hardware.
slouken@0
   986
	   This is necessary since finfo.line_length changes.
slouken@0
   987
	 */
slouken@0
   988
	if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
slouken@0
   989
		SDL_SetError("Couldn't get console hardware info");
slouken@0
   990
		return(NULL);
slouken@0
   991
	}
slouken@0
   992
slouken@0
   993
	/* Save hardware palette, if needed */
slouken@0
   994
	FB_SavePalette(this, &finfo, &vinfo);
slouken@0
   995
slouken@0
   996
	/* Set up the new mode framebuffer */
slouken@0
   997
	current->flags = (SDL_FULLSCREEN|SDL_HWSURFACE);
slouken@0
   998
	current->w = vinfo.xres;
slouken@0
   999
	current->h = vinfo.yres;
slouken@0
  1000
	current->pitch = finfo.line_length;
slouken@0
  1001
	current->pixels = mapped_mem+mapped_offset;
slouken@0
  1002
slouken@106
  1003
	/* Set up the information for hardware surfaces */
slouken@106
  1004
	surfaces_mem = (char *)current->pixels +
slouken@106
  1005
	                        vinfo.yres_virtual*current->pitch;
slouken@106
  1006
	surfaces_len = (mapped_memlen-(surfaces_mem-mapped_mem));
slouken@106
  1007
	FB_FreeHWSurfaces(this);
slouken@106
  1008
	FB_InitHWSurfaces(this, current, surfaces_mem, surfaces_len);
slouken@106
  1009
slouken@0
  1010
	/* Let the application know we have a hardware palette */
slouken@0
  1011
	switch (finfo.visual) {
slouken@0
  1012
	    case FB_VISUAL_PSEUDOCOLOR:
slouken@0
  1013
		current->flags |= SDL_HWPALETTE;
slouken@0
  1014
		break;
slouken@0
  1015
	    default:
slouken@0
  1016
		break;
slouken@0
  1017
	}
slouken@0
  1018
slouken@0
  1019
	/* Update for double-buffering, if we can */
slouken@0
  1020
	if ( flags & SDL_DOUBLEBUF ) {
slouken@0
  1021
		if ( vinfo.yres_virtual == (height*2) ) {
slouken@0
  1022
			current->flags |= SDL_DOUBLEBUF;
slouken@0
  1023
			flip_page = 0;
slouken@0
  1024
			flip_address[0] = (char *)current->pixels;
slouken@0
  1025
			flip_address[1] = (char *)current->pixels+
slouken@0
  1026
			                          current->h*current->pitch;
slouken@106
  1027
			this->screen = current;
slouken@0
  1028
			FB_FlipHWSurface(this, current);
slouken@106
  1029
			this->screen = NULL;
slouken@0
  1030
		}
slouken@0
  1031
	}
slouken@0
  1032
slouken@0
  1033
	/* Set the update rectangle function */
slouken@0
  1034
	this->UpdateRects = FB_DirectUpdate;
slouken@0
  1035
slouken@0
  1036
	/* We're done */
slouken@0
  1037
	return(current);
slouken@0
  1038
}
slouken@0
  1039
slouken@0
  1040
#ifdef FBCON_DEBUG
slouken@0
  1041
void FB_DumpHWSurfaces(_THIS)
slouken@0
  1042
{
slouken@0
  1043
	vidmem_bucket *bucket;
slouken@0
  1044
slouken@0
  1045
	printf("Memory left: %d (%d total)\n", surfaces_memleft, surfaces_memtotal);
slouken@0
  1046
	printf("\n");
slouken@0
  1047
	printf("         Base  Size\n");
slouken@0
  1048
	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
slouken@0
  1049
		printf("Bucket:  %p, %d (%s)\n", bucket->base, bucket->size, bucket->used ? "used" : "free");
slouken@0
  1050
		if ( bucket->prev ) {
slouken@0
  1051
			if ( bucket->base != bucket->prev->base+bucket->prev->size ) {
slouken@0
  1052
				printf("Warning, corrupt bucket list! (prev)\n");
slouken@0
  1053
			}
slouken@0
  1054
		} else {
slouken@0
  1055
			if ( bucket != &surfaces ) {
slouken@0
  1056
				printf("Warning, corrupt bucket list! (!prev)\n");
slouken@0
  1057
			}
slouken@0
  1058
		}
slouken@0
  1059
		if ( bucket->next ) {
slouken@0
  1060
			if ( bucket->next->base != bucket->base+bucket->size ) {
slouken@0
  1061
				printf("Warning, corrupt bucket list! (next)\n");
slouken@0
  1062
			}
slouken@0
  1063
		}
slouken@0
  1064
	}
slouken@0
  1065
	printf("\n");
slouken@0
  1066
}
slouken@0
  1067
#endif
slouken@0
  1068
slouken@106
  1069
static int FB_InitHWSurfaces(_THIS, SDL_Surface *screen, char *base, int size)
slouken@0
  1070
{
slouken@106
  1071
	vidmem_bucket *bucket;
slouken@106
  1072
slouken@0
  1073
	surfaces_memtotal = size;
slouken@0
  1074
	surfaces_memleft = size;
slouken@106
  1075
slouken@106
  1076
	if ( surfaces_memleft > 0 ) {
slouken@106
  1077
		bucket = (vidmem_bucket *)malloc(sizeof(*bucket));
slouken@106
  1078
		if ( bucket == NULL ) {
slouken@106
  1079
			SDL_OutOfMemory();
slouken@106
  1080
			return(-1);
slouken@106
  1081
		}
slouken@106
  1082
		bucket->prev = &surfaces;
slouken@106
  1083
		bucket->used = 0;
slouken@106
  1084
		bucket->dirty = 0;
slouken@106
  1085
		bucket->base = base;
slouken@106
  1086
		bucket->size = size;
slouken@106
  1087
		bucket->next = NULL;
slouken@106
  1088
	} else {
slouken@106
  1089
		bucket = NULL;
slouken@106
  1090
	}
slouken@106
  1091
slouken@106
  1092
	surfaces.prev = NULL;
slouken@106
  1093
	surfaces.used = 1;
slouken@106
  1094
	surfaces.dirty = 0;
slouken@106
  1095
	surfaces.base = screen->pixels;
slouken@106
  1096
	surfaces.size = (unsigned int)((long)base - (long)surfaces.base);
slouken@106
  1097
	surfaces.next = bucket;
slouken@106
  1098
	screen->hwdata = (struct private_hwdata *)&surfaces;
slouken@0
  1099
	return(0);
slouken@0
  1100
}
slouken@0
  1101
static void FB_FreeHWSurfaces(_THIS)
slouken@0
  1102
{
slouken@0
  1103
	vidmem_bucket *bucket, *freeable;
slouken@0
  1104
slouken@0
  1105
	bucket = surfaces.next;
slouken@0
  1106
	while ( bucket ) {
slouken@0
  1107
		freeable = bucket;
slouken@0
  1108
		bucket = bucket->next;
slouken@0
  1109
		free(freeable);
slouken@0
  1110
	}
slouken@0
  1111
	surfaces.next = NULL;
slouken@0
  1112
}
slouken@0
  1113
slouken@0
  1114
static int FB_AllocHWSurface(_THIS, SDL_Surface *surface)
slouken@0
  1115
{
slouken@0
  1116
	vidmem_bucket *bucket;
slouken@0
  1117
	int size;
slouken@0
  1118
	int extra;
slouken@0
  1119
slouken@0
  1120
/* Temporarily, we only allow surfaces the same width as display.
slouken@0
  1121
   Some blitters require the pitch between two hardware surfaces
slouken@0
  1122
   to be the same.  Others have interesting alignment restrictions.
slouken@0
  1123
   Until someone who knows these details looks at the code...
slouken@0
  1124
*/
slouken@0
  1125
if ( surface->pitch > SDL_VideoSurface->pitch ) {
slouken@0
  1126
	SDL_SetError("Surface requested wider than screen");
slouken@0
  1127
	return(-1);
slouken@0
  1128
}
slouken@0
  1129
surface->pitch = SDL_VideoSurface->pitch;
slouken@0
  1130
	size = surface->h * surface->pitch;
slouken@0
  1131
#ifdef FBCON_DEBUG
slouken@0
  1132
	fprintf(stderr, "Allocating bucket of %d bytes\n", size);
slouken@0
  1133
#endif
slouken@0
  1134
slouken@0
  1135
	/* Quick check for available mem */
slouken@0
  1136
	if ( size > surfaces_memleft ) {
slouken@0
  1137
		SDL_SetError("Not enough video memory");
slouken@0
  1138
		return(-1);
slouken@0
  1139
	}
slouken@0
  1140
slouken@0
  1141
	/* Search for an empty bucket big enough */
slouken@0
  1142
	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
slouken@0
  1143
		if ( ! bucket->used && (size <= bucket->size) ) {
slouken@0
  1144
			break;
slouken@0
  1145
		}
slouken@0
  1146
	}
slouken@0
  1147
	if ( bucket == NULL ) {
slouken@0
  1148
		SDL_SetError("Video memory too fragmented");
slouken@0
  1149
		return(-1);
slouken@0
  1150
	}
slouken@0
  1151
slouken@0
  1152
	/* Create a new bucket for left-over memory */
slouken@0
  1153
	extra = (bucket->size - size);
slouken@0
  1154
	if ( extra ) {
slouken@0
  1155
		vidmem_bucket *newbucket;
slouken@0
  1156
slouken@0
  1157
#ifdef FBCON_DEBUG
slouken@0
  1158
	fprintf(stderr, "Adding new free bucket of %d bytes\n", extra);
slouken@0
  1159
#endif
slouken@0
  1160
		newbucket = (vidmem_bucket *)malloc(sizeof(*newbucket));
slouken@0
  1161
		if ( newbucket == NULL ) {
slouken@0
  1162
			SDL_OutOfMemory();
slouken@0
  1163
			return(-1);
slouken@0
  1164
		}
slouken@0
  1165
		newbucket->prev = bucket;
slouken@0
  1166
		newbucket->used = 0;
slouken@0
  1167
		newbucket->base = bucket->base+size;
slouken@0
  1168
		newbucket->size = extra;
slouken@0
  1169
		newbucket->next = bucket->next;
slouken@0
  1170
		if ( bucket->next ) {
slouken@0
  1171
			bucket->next->prev = newbucket;
slouken@0
  1172
		}
slouken@0
  1173
		bucket->next = newbucket;
slouken@0
  1174
	}
slouken@0
  1175
slouken@0
  1176
	/* Set the current bucket values and return it! */
slouken@0
  1177
	bucket->used = 1;
slouken@0
  1178
	bucket->size = size;
slouken@106
  1179
	bucket->dirty = 0;
slouken@0
  1180
#ifdef FBCON_DEBUG
slouken@0
  1181
	fprintf(stderr, "Allocated %d bytes at %p\n", bucket->size, bucket->base);
slouken@0
  1182
#endif
slouken@0
  1183
	surfaces_memleft -= size;
slouken@0
  1184
	surface->flags |= SDL_HWSURFACE;
slouken@0
  1185
	surface->pixels = bucket->base;
slouken@106
  1186
	surface->hwdata = (struct private_hwdata *)bucket;
slouken@0
  1187
	return(0);
slouken@0
  1188
}
slouken@0
  1189
static void FB_FreeHWSurface(_THIS, SDL_Surface *surface)
slouken@0
  1190
{
slouken@0
  1191
	vidmem_bucket *bucket, *freeable;
slouken@0
  1192
slouken@0
  1193
	/* Look for the bucket in the current list */
slouken@0
  1194
	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
slouken@106
  1195
		if ( bucket == (vidmem_bucket *)surface->hwdata ) {
slouken@0
  1196
			break;
slouken@0
  1197
		}
slouken@0
  1198
	}
slouken@106
  1199
	if ( bucket && bucket->used ) {
slouken@106
  1200
		/* Add the memory back to the total */
slouken@106
  1201
#ifdef DGA_DEBUG
slouken@0
  1202
	printf("Freeing bucket of %d bytes\n", bucket->size);
slouken@0
  1203
#endif
slouken@106
  1204
		surfaces_memleft += bucket->size;
slouken@0
  1205
slouken@106
  1206
		/* Can we merge the space with surrounding buckets? */
slouken@106
  1207
		bucket->used = 0;
slouken@106
  1208
		if ( bucket->next && ! bucket->next->used ) {
slouken@106
  1209
#ifdef DGA_DEBUG
slouken@0
  1210
	printf("Merging with next bucket, for %d total bytes\n", bucket->size+bucket->next->size);
slouken@0
  1211
#endif
slouken@106
  1212
			freeable = bucket->next;
slouken@106
  1213
			bucket->size += bucket->next->size;
slouken@106
  1214
			bucket->next = bucket->next->next;
slouken@106
  1215
			if ( bucket->next ) {
slouken@106
  1216
				bucket->next->prev = bucket;
slouken@106
  1217
			}
slouken@106
  1218
			free(freeable);
slouken@0
  1219
		}
slouken@106
  1220
		if ( bucket->prev && ! bucket->prev->used ) {
slouken@106
  1221
#ifdef DGA_DEBUG
slouken@0
  1222
	printf("Merging with previous bucket, for %d total bytes\n", bucket->prev->size+bucket->size);
slouken@0
  1223
#endif
slouken@106
  1224
			freeable = bucket;
slouken@106
  1225
			bucket->prev->size += bucket->size;
slouken@106
  1226
			bucket->prev->next = bucket->next;
slouken@106
  1227
			if ( bucket->next ) {
slouken@106
  1228
				bucket->next->prev = bucket->prev;
slouken@106
  1229
			}
slouken@106
  1230
			free(freeable);
slouken@0
  1231
		}
slouken@0
  1232
	}
slouken@0
  1233
	surface->pixels = NULL;
slouken@106
  1234
	surface->hwdata = NULL;
slouken@0
  1235
}
slouken@0
  1236
static int FB_LockHWSurface(_THIS, SDL_Surface *surface)
slouken@0
  1237
{
slouken@106
  1238
	if ( surface == this->screen ) {
slouken@0
  1239
		SDL_mutexP(hw_lock);
slouken@106
  1240
		if ( FB_IsSurfaceBusy(surface) ) {
slouken@106
  1241
			FB_WaitBusySurfaces(this);
slouken@106
  1242
		}
slouken@106
  1243
	} else {
slouken@106
  1244
		if ( FB_IsSurfaceBusy(surface) ) {
slouken@106
  1245
			FB_WaitBusySurfaces(this);
slouken@106
  1246
		}
slouken@0
  1247
	}
slouken@0
  1248
	return(0);
slouken@0
  1249
}
slouken@0
  1250
static void FB_UnlockHWSurface(_THIS, SDL_Surface *surface)
slouken@0
  1251
{
slouken@106
  1252
	if ( surface == this->screen ) {
slouken@0
  1253
		SDL_mutexV(hw_lock);
slouken@0
  1254
	}
slouken@0
  1255
}
slouken@0
  1256
slouken@0
  1257
static void FB_WaitVBL(_THIS)
slouken@0
  1258
{
slouken@0
  1259
#ifdef FBIOWAITRETRACE /* Heheh, this didn't make it into the main kernel */
slouken@0
  1260
	ioctl(console_fd, FBIOWAITRETRACE, 0);
slouken@0
  1261
#endif
slouken@0
  1262
	return;
slouken@0
  1263
}
slouken@0
  1264
slouken@106
  1265
static void FB_WaitIdle(_THIS)
slouken@106
  1266
{
slouken@106
  1267
	return;
slouken@106
  1268
}
slouken@106
  1269
slouken@0
  1270
static int FB_FlipHWSurface(_THIS, SDL_Surface *surface)
slouken@0
  1271
{
slouken@0
  1272
	/* Wait for vertical retrace and then flip display */
slouken@0
  1273
	cache_vinfo.yoffset = flip_page*surface->h;
slouken@106
  1274
	if ( FB_IsSurfaceBusy(this->screen) ) {
slouken@106
  1275
		FB_WaitBusySurfaces(this);
slouken@106
  1276
	}
slouken@0
  1277
	wait_vbl(this);
slouken@0
  1278
	if ( ioctl(console_fd, FBIOPAN_DISPLAY, &cache_vinfo) < 0 ) {
slouken@0
  1279
		SDL_SetError("ioctl(FBIOPAN_DISPLAY) failed");
slouken@0
  1280
		return(-1);
slouken@0
  1281
	}
slouken@0
  1282
	flip_page = !flip_page;
slouken@0
  1283
slouken@0
  1284
	surface->pixels = flip_address[flip_page];
slouken@0
  1285
	return(0);
slouken@0
  1286
}
slouken@0
  1287
slouken@0
  1288
static void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
slouken@0
  1289
{
slouken@0
  1290
	/* The application is already updating the visible video memory */
slouken@0
  1291
	return;
slouken@0
  1292
}
slouken@0
  1293
slouken@0
  1294
#ifdef VGA16_FBCON_SUPPORT
slouken@0
  1295
/* Code adapted with thanks from the XFree86 VGA16 driver! :) */
slouken@0
  1296
#define writeGr(index, value) \
slouken@0
  1297
outb(index, 0x3CE);           \
slouken@0
  1298
outb(value, 0x3CF);
slouken@0
  1299
#define writeSeq(index, value) \
slouken@0
  1300
outb(index, 0x3C4);            \
slouken@0
  1301
outb(value, 0x3C5);
slouken@0
  1302
slouken@0
  1303
static void FB_VGA16Update(_THIS, int numrects, SDL_Rect *rects)
slouken@0
  1304
{
slouken@0
  1305
    SDL_Surface *screen;
slouken@0
  1306
    int width, height, FBPitch, left, i, j, SRCPitch, phase;
slouken@0
  1307
    register Uint32 m;
slouken@0
  1308
    Uint8  s1, s2, s3, s4;
slouken@0
  1309
    Uint32 *src, *srcPtr;
slouken@0
  1310
    Uint8  *dst, *dstPtr;
slouken@0
  1311
slouken@0
  1312
    screen = this->screen;
slouken@0
  1313
    FBPitch = screen->w >> 3;
slouken@0
  1314
    SRCPitch = screen->pitch >> 2;
slouken@0
  1315
slouken@0
  1316
    writeGr(0x03, 0x00);
slouken@0
  1317
    writeGr(0x05, 0x00);
slouken@0
  1318
    writeGr(0x01, 0x00);
slouken@0
  1319
    writeGr(0x08, 0xFF);
slouken@0
  1320
slouken@0
  1321
    while(numrects--) {
slouken@0
  1322
	left = rects->x & ~7;
slouken@0
  1323
        width = (rects->w + 7) >> 3;
slouken@0
  1324
        height = rects->h;
slouken@0
  1325
        src = (Uint32*)screen->pixels + (rects->y * SRCPitch) + (left >> 2); 
slouken@0
  1326
        dst = (Uint8*)mapped_mem + (rects->y * FBPitch) + (left >> 3);
slouken@0
  1327
slouken@0
  1328
	if((phase = (long)dst & 3L)) {
slouken@0
  1329
	    phase = 4 - phase;
slouken@0
  1330
	    if(phase > width) phase = width;
slouken@0
  1331
	    width -= phase;
slouken@0
  1332
	}
slouken@0
  1333
slouken@0
  1334
        while(height--) {
slouken@0
  1335
	    writeSeq(0x02, 1 << 0);
slouken@0
  1336
	    dstPtr = dst;
slouken@0
  1337
	    srcPtr = src;
slouken@0
  1338
	    i = width;
slouken@0
  1339
	    j = phase;
slouken@0
  1340
	    while(j--) {
slouken@0
  1341
		m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4);
slouken@0
  1342
 		*dstPtr++ = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
slouken@0
  1343
		srcPtr += 2;
slouken@0
  1344
	    }
slouken@0
  1345
	    while(i >= 4) {
slouken@0
  1346
		m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4);
slouken@0
  1347
 		s1 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
slouken@0
  1348
		m = (srcPtr[3] & 0x01010101) | ((srcPtr[2] & 0x01010101) << 4);
slouken@0
  1349
 		s2 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
slouken@0
  1350
		m = (srcPtr[5] & 0x01010101) | ((srcPtr[4] & 0x01010101) << 4);
slouken@0
  1351
 		s3 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
slouken@0
  1352
		m = (srcPtr[7] & 0x01010101) | ((srcPtr[6] & 0x01010101) << 4);
slouken@0
  1353
 		s4 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
slouken@0
  1354
		*((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
slouken@0
  1355
		srcPtr += 8;
slouken@0
  1356
		dstPtr += 4;
slouken@0
  1357
		i -= 4;
slouken@0
  1358
	    }
slouken@0
  1359
	    while(i--) {
slouken@0
  1360
		m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4);
slouken@0
  1361
 		*dstPtr++ = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
slouken@0
  1362
		srcPtr += 2;
slouken@0
  1363
	    }
slouken@0
  1364
slouken@0
  1365
	    writeSeq(0x02, 1 << 1);
slouken@0
  1366
	    dstPtr = dst;
slouken@0
  1367
	    srcPtr = src;
slouken@0
  1368
	    i = width;
slouken@0
  1369
	    j = phase;
slouken@0
  1370
	    while(j--) {
slouken@0
  1371
		m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4);
slouken@0
  1372
 		*dstPtr++ = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
slouken@0
  1373
		srcPtr += 2;
slouken@0
  1374
	    }
slouken@0
  1375
	    while(i >= 4) {
slouken@0
  1376
		m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4);
slouken@0
  1377
 		s1 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
slouken@0
  1378
		m = (srcPtr[3] & 0x02020202) | ((srcPtr[2] & 0x02020202) << 4);
slouken@0
  1379
 		s2 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
slouken@0
  1380
		m = (srcPtr[5] & 0x02020202) | ((srcPtr[4] & 0x02020202) << 4);
slouken@0
  1381
 		s3 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
slouken@0
  1382
		m = (srcPtr[7] & 0x02020202) | ((srcPtr[6] & 0x02020202) << 4);
slouken@0
  1383
 		s4 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
slouken@0
  1384
		*((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
slouken@0
  1385
		srcPtr += 8;
slouken@0
  1386
		dstPtr += 4;
slouken@0
  1387
		i -= 4;
slouken@0
  1388
	    }
slouken@0
  1389
	    while(i--) {
slouken@0
  1390
		m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4);
slouken@0
  1391
 		*dstPtr++ = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
slouken@0
  1392
		srcPtr += 2;
slouken@0
  1393
	    }
slouken@0
  1394
slouken@0
  1395
	    writeSeq(0x02, 1 << 2);
slouken@0
  1396
	    dstPtr = dst;
slouken@0
  1397
	    srcPtr = src;
slouken@0
  1398
	    i = width;
slouken@0
  1399
	    j = phase;
slouken@0
  1400
	    while(j--) {
slouken@0
  1401
		m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4);
slouken@0
  1402
 		*dstPtr++ = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
slouken@0
  1403
		srcPtr += 2;
slouken@0
  1404
	    }
slouken@0
  1405
	    while(i >= 4) {
slouken@0
  1406
		m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4);
slouken@0
  1407
 		s1 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
slouken@0
  1408
		m = (srcPtr[3] & 0x04040404) | ((srcPtr[2] & 0x04040404) << 4);
slouken@0
  1409
 		s2 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
slouken@0
  1410
		m = (srcPtr[5] & 0x04040404) | ((srcPtr[4] & 0x04040404) << 4);
slouken@0
  1411
 		s3 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
slouken@0
  1412
		m = (srcPtr[7] & 0x04040404) | ((srcPtr[6] & 0x04040404) << 4);
slouken@0
  1413
 		s4 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
slouken@0
  1414
		*((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
slouken@0
  1415
		srcPtr += 8;
slouken@0
  1416
		dstPtr += 4;
slouken@0
  1417
		i -= 4;
slouken@0
  1418
	    }
slouken@0
  1419
	    while(i--) {
slouken@0
  1420
		m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4);
slouken@0
  1421
 		*dstPtr++ = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
slouken@0
  1422
		srcPtr += 2;
slouken@0
  1423
	    }
slouken@0
  1424
	    
slouken@0
  1425
	    writeSeq(0x02, 1 << 3);
slouken@0
  1426
	    dstPtr = dst;
slouken@0
  1427
	    srcPtr = src;
slouken@0
  1428
	    i = width;
slouken@0
  1429
	    j = phase;
slouken@0
  1430
	    while(j--) {
slouken@0
  1431
		m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4);
slouken@0
  1432
 		*dstPtr++ = (m >> 27) | (m >> 18) | (m >> 9) | m;
slouken@0
  1433
		srcPtr += 2;
slouken@0
  1434
	    }
slouken@0
  1435
	    while(i >= 4) {
slouken@0
  1436
		m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4);
slouken@0
  1437
 		s1 = (m >> 27) | (m >> 18) | (m >> 9) | m;
slouken@0
  1438
		m = (srcPtr[3] & 0x08080808) | ((srcPtr[2] & 0x08080808) << 4);
slouken@0
  1439
 		s2 = (m >> 27) | (m >> 18) | (m >> 9) | m;
slouken@0
  1440
		m = (srcPtr[5] & 0x08080808) | ((srcPtr[4] & 0x08080808) << 4);
slouken@0
  1441
 		s3 = (m >> 27) | (m >> 18) | (m >> 9) | m;
slouken@0
  1442
		m = (srcPtr[7] & 0x08080808) | ((srcPtr[6] & 0x08080808) << 4);
slouken@0
  1443
 		s4 = (m >> 27) | (m >> 18) | (m >> 9) | m;
slouken@0
  1444
		*((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
slouken@0
  1445
		srcPtr += 8;
slouken@0
  1446
		dstPtr += 4;
slouken@0
  1447
		i -= 4;
slouken@0
  1448
	    }
slouken@0
  1449
	    while(i--) {
slouken@0
  1450
		m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4);
slouken@0
  1451
 		*dstPtr++ = (m >> 27) | (m >> 18) | (m >> 9) | m;
slouken@0
  1452
		srcPtr += 2;
slouken@0
  1453
	    }
slouken@0
  1454
slouken@0
  1455
            dst += FBPitch;
slouken@0
  1456
            src += SRCPitch;
slouken@0
  1457
        }
slouken@0
  1458
        rects++;
slouken@0
  1459
    }
slouken@0
  1460
}
slouken@0
  1461
#endif /* VGA16_FBCON_SUPPORT */
slouken@0
  1462
slouken@0
  1463
void FB_SavePaletteTo(_THIS, int palette_len, __u16 *area)
slouken@0
  1464
{
slouken@0
  1465
	struct fb_cmap cmap;
slouken@0
  1466
slouken@0
  1467
	cmap.start = 0;
slouken@0
  1468
	cmap.len = palette_len;
slouken@0
  1469
	cmap.red = &area[0*palette_len];
slouken@0
  1470
	cmap.green = &area[1*palette_len];
slouken@0
  1471
	cmap.blue = &area[2*palette_len];
slouken@0
  1472
	cmap.transp = NULL;
slouken@0
  1473
	ioctl(console_fd, FBIOGETCMAP, &cmap);
slouken@0
  1474
}
slouken@0
  1475
slouken@0
  1476
void FB_RestorePaletteFrom(_THIS, int palette_len, __u16 *area)
slouken@0
  1477
{
slouken@0
  1478
	struct fb_cmap cmap;
slouken@0
  1479
slouken@0
  1480
	cmap.start = 0;
slouken@0
  1481
	cmap.len = palette_len;
slouken@0
  1482
	cmap.red = &area[0*palette_len];
slouken@0
  1483
	cmap.green = &area[1*palette_len];
slouken@0
  1484
	cmap.blue = &area[2*palette_len];
slouken@0
  1485
	cmap.transp = NULL;
slouken@0
  1486
	ioctl(console_fd, FBIOPUTCMAP, &cmap);
slouken@0
  1487
}
slouken@0
  1488
slouken@0
  1489
static void FB_SavePalette(_THIS, struct fb_fix_screeninfo *finfo,
slouken@0
  1490
                                  struct fb_var_screeninfo *vinfo)
slouken@0
  1491
{
slouken@0
  1492
	int i;
slouken@0
  1493
slouken@0
  1494
	/* Save hardware palette, if needed */
slouken@0
  1495
	if ( finfo->visual == FB_VISUAL_PSEUDOCOLOR ) {
slouken@0
  1496
		saved_cmaplen = 1<<vinfo->bits_per_pixel;
slouken@0
  1497
		saved_cmap=(__u16 *)malloc(3*saved_cmaplen*sizeof(*saved_cmap));
slouken@0
  1498
		if ( saved_cmap != NULL ) {
slouken@0
  1499
			FB_SavePaletteTo(this, saved_cmaplen, saved_cmap);
slouken@0
  1500
		}
slouken@0
  1501
	}
slouken@0
  1502
slouken@0
  1503
	/* Added support for FB_VISUAL_DIRECTCOLOR.
slouken@0
  1504
	   With this mode pixel information is passed through the palette...
slouken@0
  1505
	   Neat fading and gamma correction effects can be had by simply
slouken@0
  1506
	   fooling around with the palette instead of changing the pixel
slouken@0
  1507
	   values themselves... Very neat!
slouken@0
  1508
slouken@0
  1509
	   Adam Meyerowitz 1/19/2000
slouken@0
  1510
	   ameyerow@optonline.com
slouken@0
  1511
	*/
slouken@0
  1512
	if ( finfo->visual == FB_VISUAL_DIRECTCOLOR ) {
slouken@0
  1513
		__u16 new_entries[3*256];
slouken@0
  1514
slouken@0
  1515
		/* Save the colormap */
slouken@0
  1516
		saved_cmaplen = 256;
slouken@0
  1517
		saved_cmap=(__u16 *)malloc(3*saved_cmaplen*sizeof(*saved_cmap));
slouken@0
  1518
		if ( saved_cmap != NULL ) {
slouken@0
  1519
			FB_SavePaletteTo(this, saved_cmaplen, saved_cmap);
slouken@0
  1520
		}
slouken@0
  1521
slouken@0
  1522
		/* Allocate new identity colormap */
slouken@0
  1523
		for ( i=0; i<256; ++i ) {
slouken@0
  1524
	      		new_entries[(0*256)+i] =
slouken@0
  1525
			new_entries[(1*256)+i] =
slouken@0
  1526
			new_entries[(2*256)+i] = (i<<8)|i;
slouken@0
  1527
		}
slouken@0
  1528
		FB_RestorePaletteFrom(this, 256, new_entries);
slouken@0
  1529
	}
slouken@0
  1530
}
slouken@0
  1531
slouken@0
  1532
static void FB_RestorePalette(_THIS)
slouken@0
  1533
{
slouken@0
  1534
	/* Restore the original palette */
slouken@0
  1535
	if ( saved_cmap ) {
slouken@0
  1536
		FB_RestorePaletteFrom(this, saved_cmaplen, saved_cmap);
slouken@0
  1537
		free(saved_cmap);
slouken@0
  1538
		saved_cmap = NULL;
slouken@0
  1539
	}
slouken@0
  1540
}
slouken@0
  1541
slouken@0
  1542
static int FB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
slouken@0
  1543
{
slouken@0
  1544
	int i;
slouken@0
  1545
	__u16 r[256];
slouken@0
  1546
	__u16 g[256];
slouken@0
  1547
	__u16 b[256];
slouken@0
  1548
	struct fb_cmap cmap;
slouken@0
  1549
slouken@0
  1550
	/* Set up the colormap */
slouken@0
  1551
	for (i = 0; i < ncolors; i++) {
slouken@0
  1552
		r[i] = colors[i].r << 8;
slouken@0
  1553
		g[i] = colors[i].g << 8;
slouken@0
  1554
		b[i] = colors[i].b << 8;
slouken@0
  1555
	}
slouken@0
  1556
	cmap.start = firstcolor;
slouken@0
  1557
	cmap.len = ncolors;
slouken@0
  1558
	cmap.red = r;
slouken@0
  1559
	cmap.green = g;
slouken@0
  1560
	cmap.blue = b;
slouken@0
  1561
	cmap.transp = NULL;
slouken@0
  1562
slouken@0
  1563
	if( (ioctl(console_fd, FBIOPUTCMAP, &cmap) < 0) ||
slouken@0
  1564
	    !(this->screen->flags & SDL_HWPALETTE) ) {
slouken@0
  1565
	        colors = this->screen->format->palette->colors;
slouken@0
  1566
		ncolors = this->screen->format->palette->ncolors;
slouken@0
  1567
		cmap.start = 0;
slouken@0
  1568
		cmap.len = ncolors;
slouken@0
  1569
		memset(r, 0, sizeof(r));
slouken@0
  1570
		memset(g, 0, sizeof(g));
slouken@0
  1571
		memset(b, 0, sizeof(b));
slouken@0
  1572
		if ( ioctl(console_fd, FBIOGETCMAP, &cmap) == 0 ) {
slouken@0
  1573
			for ( i=ncolors-1; i>=0; --i ) {
slouken@0
  1574
				colors[i].r = (r[i]>>8);
slouken@0
  1575
				colors[i].g = (g[i]>>8);
slouken@0
  1576
				colors[i].b = (b[i]>>8);
slouken@0
  1577
			}
slouken@0
  1578
		}
slouken@0
  1579
		return(0);
slouken@0
  1580
	}
slouken@0
  1581
	return(1);
slouken@0
  1582
}
slouken@0
  1583
slouken@0
  1584
/* Note:  If we are terminated, this could be called in the middle of
slouken@0
  1585
   another SDL video routine -- notably UpdateRects.
slouken@0
  1586
*/
slouken@0
  1587
static void FB_VideoQuit(_THIS)
slouken@0
  1588
{
slouken@0
  1589
	int i, j;
slouken@0
  1590
slouken@0
  1591
	if ( this->screen ) {
slouken@0
  1592
		/* Clear screen and tell SDL not to free the pixels */
slouken@0
  1593
		if ( this->screen->pixels && FB_InGraphicsMode(this) ) {
slouken@1036
  1594
#if defined(__powerpc__) || defined(__ia64__)	/* SIGBUS when using memset() ?? */
slouken@0
  1595
			Uint8 *rowp = (Uint8 *)this->screen->pixels;
slouken@0
  1596
			int left = this->screen->pitch*this->screen->h;
slouken@0
  1597
			while ( left-- ) { *rowp++ = 0; }
slouken@0
  1598
#else
slouken@0
  1599
			memset(this->screen->pixels,0,this->screen->h*this->screen->pitch);
slouken@0
  1600
#endif
slouken@0
  1601
		}
slouken@0
  1602
		/* This test fails when using the VGA16 shadow memory */
slouken@0
  1603
		if ( ((char *)this->screen->pixels >= mapped_mem) &&
slouken@0
  1604
		     ((char *)this->screen->pixels < (mapped_mem+mapped_memlen)) ) {
slouken@0
  1605
			this->screen->pixels = NULL;
slouken@0
  1606
		}
slouken@0
  1607
	}
slouken@0
  1608
slouken@0
  1609
	/* Clear the lock mutex */
slouken@0
  1610
	if ( hw_lock ) {
slouken@0
  1611
		SDL_DestroyMutex(hw_lock);
slouken@0
  1612
		hw_lock = NULL;
slouken@0
  1613
	}
slouken@0
  1614
slouken@0
  1615
	/* Clean up defined video modes */
slouken@0
  1616
	for ( i=0; i<NUM_MODELISTS; ++i ) {
slouken@0
  1617
		if ( SDL_modelist[i] != NULL ) {
slouken@0
  1618
			for ( j=0; SDL_modelist[i][j]; ++j ) {
slouken@0
  1619
				free(SDL_modelist[i][j]);
slouken@0
  1620
			}
slouken@0
  1621
			free(SDL_modelist[i]);
slouken@0
  1622
			SDL_modelist[i] = NULL;
slouken@0
  1623
		}
slouken@0
  1624
	}
slouken@0
  1625
slouken@0
  1626
	/* Clean up the memory bucket list */
slouken@0
  1627
	FB_FreeHWSurfaces(this);
slouken@0
  1628
slouken@0
  1629
	/* Close console and input file descriptors */
slouken@0
  1630
	if ( console_fd > 0 ) {
slouken@0
  1631
		/* Unmap the video framebuffer and I/O registers */
slouken@0
  1632
		if ( mapped_mem ) {
slouken@0
  1633
			munmap(mapped_mem, mapped_memlen);
slouken@0
  1634
			mapped_mem = NULL;
slouken@0
  1635
		}
slouken@0
  1636
		if ( mapped_io ) {
slouken@0
  1637
			munmap(mapped_io, mapped_iolen);
slouken@0
  1638
			mapped_io = NULL;
slouken@0
  1639
		}
slouken@0
  1640
slouken@0
  1641
		/* Restore the original video mode and palette */
slouken@0
  1642
		if ( FB_InGraphicsMode(this) ) {
slouken@0
  1643
			FB_RestorePalette(this);
slouken@0
  1644
			ioctl(console_fd, FBIOPUT_VSCREENINFO, &saved_vinfo);
slouken@0
  1645
		}
slouken@0
  1646
slouken@0
  1647
		/* We're all done with the framebuffer */
slouken@0
  1648
		close(console_fd);
slouken@0
  1649
		console_fd = -1;
slouken@0
  1650
	}
slouken@0
  1651
	FB_CloseMouse(this);
slouken@0
  1652
	FB_CloseKeyboard(this);
slouken@0
  1653
}