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