src/video/fbcon/SDL_fbvideo.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. outb
  2. FB_Available
  3. FB_DeleteDevice
  4. FB_CreateDevice
  5. FB_CheckMode
  6. FB_AddMode
  7. FB_VideoInit
  8. FB_ListModes
  9. print_vinfo
  10. print_finfo
  11. choose_fbmodes_mode
  12. choose_vesa_mode
  13. FB_SetVGA16Mode
  14. FB_SetVideoMode
  15. FB_DumpHWSurfaces
  16. FB_InitHWSurfaces
  17. FB_FreeHWSurfaces
  18. FB_AllocHWSurface
  19. FB_FreeHWSurface
  20. FB_LockHWSurface
  21. FB_UnlockHWSurface
  22. FB_WaitVBL
  23. FB_FlipHWSurface
  24. FB_DirectUpdate
  25. writeGr
  26. writeSeq
  27. FB_VGA16Update
  28. FB_SavePaletteTo
  29. FB_RestorePaletteFrom
  30. FB_SavePalette
  31. FB_RestorePalette
  32. FB_SetColors
  33. FB_VideoQuit

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

/* [<][>][^][v][top][bottom][index][help] */