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