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