src/video/vgl/SDL_vglvideo.c
author Edgar Simo <bobbens@gmail.com>
Sun, 06 Jul 2008 17:06:37 +0000
branchgsoc2008_force_feedback
changeset 2498 ab567bd667bf
parent 1895 c121d94672cb
child 2698 e1da92da346c
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 /* libvga based SDL video driver implementation.
    25 */
    26 
    27 #include <err.h>
    28 #include <osreldate.h>
    29 #include <unistd.h>
    30 #include <sys/stat.h>
    31 
    32 #include <sys/fbio.h>
    33 #include <sys/consio.h>
    34 #include <sys/kbio.h>
    35 #include <vgl.h>
    36 
    37 #include "SDL_video.h"
    38 #include "SDL_mouse.h"
    39 #include "../SDL_sysvideo.h"
    40 #include "../SDL_pixels_c.h"
    41 #include "../../events/SDL_events_c.h"
    42 #include "SDL_vglvideo.h"
    43 #include "SDL_vglevents_c.h"
    44 #include "SDL_vglmouse_c.h"
    45 
    46 
    47 /* Initialization/Query functions */
    48 static int VGL_VideoInit(_THIS, SDL_PixelFormat * vformat);
    49 static SDL_Rect **VGL_ListModes(_THIS, SDL_PixelFormat * format,
    50                                 Uint32 flags);
    51 static SDL_Surface *VGL_SetVideoMode(_THIS, SDL_Surface * current, int width,
    52                                      int height, int bpp, Uint32 flags);
    53 static int VGL_SetColors(_THIS, int firstcolor, int ncolors,
    54                          SDL_Color * colors);
    55 static void VGL_VideoQuit(_THIS);
    56 
    57 /* Hardware surface functions */
    58 static int VGL_AllocHWSurface(_THIS, SDL_Surface * surface);
    59 static int VGL_LockHWSurface(_THIS, SDL_Surface * surface);
    60 static int VGL_FlipHWSurface(_THIS, SDL_Surface * surface);
    61 static void VGL_UnlockHWSurface(_THIS, SDL_Surface * surface);
    62 static void VGL_FreeHWSurface(_THIS, SDL_Surface * surface);
    63 
    64 /* Misc function */
    65 static VGLMode **VGLListModes(int depth, int mem_model);
    66 static void VGLWaitRetrace(void);
    67 
    68 /* VGL driver bootstrap functions */
    69 
    70 static int
    71 VGL_Available(void)
    72 {
    73     /*
    74      * Check to see if we are root and stdin is a
    75      * virtual console. Also try to ensure that
    76      * modes other than 320x200 are available
    77      */
    78     int console, hires_available, i;
    79     VGLMode **modes;
    80 
    81     console = STDIN_FILENO;
    82     if (console >= 0) {
    83         struct stat sb;
    84         struct vt_mode dummy;
    85 
    86         if ((fstat(console, &sb) < 0) ||
    87             (ioctl(console, VT_GETMODE, &dummy) < 0)) {
    88             console = -1;
    89         }
    90     }
    91     if (geteuid() != 0 && console == -1)
    92         return 0;
    93 
    94     modes = VGLListModes(8, V_INFO_MM_DIRECT | V_INFO_MM_PACKED);
    95     hires_available = 0;
    96     for (i = 0; modes[i] != NULL; i++) {
    97         if ((modes[i]->ModeInfo.Xsize > 320) &&
    98             (modes[i]->ModeInfo.Ysize > 200) &&
    99             ((modes[i]->ModeInfo.Type == VIDBUF8) ||
   100              (modes[i]->ModeInfo.Type == VIDBUF16) ||
   101              (modes[i]->ModeInfo.Type == VIDBUF32))) {
   102             hires_available = 1;
   103             break;
   104         }
   105     }
   106     return hires_available;
   107 }
   108 
   109 static void
   110 VGL_DeleteDevice(SDL_VideoDevice * device)
   111 {
   112     SDL_free(device->hidden);
   113     SDL_free(device);
   114 }
   115 
   116 static SDL_VideoDevice *
   117 VGL_CreateDevice(int devindex)
   118 {
   119     SDL_VideoDevice *device;
   120 
   121     /* Initialize all variables that we clean on shutdown */
   122     device = (SDL_VideoDevice *) SDL_malloc(sizeof(SDL_VideoDevice));
   123     if (device) {
   124         SDL_memset(device, 0, (sizeof *device));
   125         device->hidden = (struct SDL_PrivateVideoData *)
   126             SDL_malloc((sizeof *device->hidden));
   127     }
   128     if ((device == NULL) || (device->hidden == NULL)) {
   129         SDL_OutOfMemory();
   130         if (device) {
   131             SDL_free(device);
   132         }
   133         return (0);
   134     }
   135     SDL_memset(device->hidden, 0, (sizeof *device->hidden));
   136 
   137     /* Set the function pointers */
   138     device->VideoInit = VGL_VideoInit;
   139     device->ListModes = VGL_ListModes;
   140     device->SetVideoMode = VGL_SetVideoMode;
   141     device->SetColors = VGL_SetColors;
   142     device->UpdateRects = NULL;
   143     device->VideoQuit = VGL_VideoQuit;
   144     device->AllocHWSurface = VGL_AllocHWSurface;
   145     device->CheckHWBlit = NULL;
   146     device->FillHWRect = NULL;
   147     device->SetHWColorKey = NULL;
   148     device->SetHWAlpha = NULL;
   149     device->LockHWSurface = VGL_LockHWSurface;
   150     device->UnlockHWSurface = VGL_UnlockHWSurface;
   151     device->FlipHWSurface = VGL_FlipHWSurface;
   152     device->FreeHWSurface = VGL_FreeHWSurface;
   153     device->SetIcon = NULL;
   154     device->SetCaption = NULL;
   155     device->GetWMInfo = NULL;
   156     device->FreeWMCursor = VGL_FreeWMCursor;
   157     device->CreateWMCursor = VGL_CreateWMCursor;
   158     device->ShowWMCursor = VGL_ShowWMCursor;
   159     device->WarpWMCursor = VGL_WarpWMCursor;
   160     device->InitOSKeymap = VGL_InitOSKeymap;
   161     device->PumpEvents = VGL_PumpEvents;
   162 
   163     device->free = VGL_DeleteDevice;
   164 
   165     return device;
   166 }
   167 
   168 VideoBootStrap VGL_bootstrap = {
   169     "vgl", "FreeBSD libVGL",
   170     VGL_Available, VGL_CreateDevice
   171 };
   172 
   173 static int
   174 VGL_AddMode(_THIS, VGLMode * inmode)
   175 {
   176     SDL_Rect *mode;
   177 
   178     int i, index;
   179     int next_mode;
   180 
   181     /* Check to see if we already have this mode */
   182     if (inmode->Depth < 8) {    /* Not supported */
   183         return 0;
   184     }
   185     index = ((inmode->Depth + 7) / 8) - 1;
   186     for (i = 0; i < SDL_nummodes[index]; ++i) {
   187         mode = SDL_modelist[index][i];
   188         if ((mode->w == inmode->ModeInfo.Xsize) &&
   189             (mode->h == inmode->ModeInfo.Ysize))
   190             return 0;
   191     }
   192 
   193     /* Set up the new video mode rectangle */
   194     mode = (SDL_Rect *) SDL_malloc(sizeof *mode);
   195     if (mode == NULL) {
   196         SDL_OutOfMemory();
   197         return -1;
   198     }
   199     mode->x = 0;
   200     mode->y = 0;
   201     mode->w = inmode->ModeInfo.Xsize;
   202     mode->h = inmode->ModeInfo.Ysize;
   203 
   204     /* Allocate the new list of modes, and fill in the new mode */
   205     next_mode = SDL_nummodes[index];
   206     SDL_modelist[index] = (SDL_Rect **)
   207         SDL_realloc(SDL_modelist[index],
   208                     (1 + next_mode + 1) * sizeof(SDL_Rect *));
   209     if (SDL_modelist[index] == NULL) {
   210         SDL_OutOfMemory();
   211         SDL_nummodes[index] = 0;
   212         SDL_free(mode);
   213         return -1;
   214     }
   215     SDL_modelist[index][next_mode] = mode;
   216     SDL_modelist[index][next_mode + 1] = NULL;
   217     SDL_nummodes[index]++;
   218 
   219     return 0;
   220 }
   221 
   222 static void
   223 VGL_UpdateVideoInfo(_THIS)
   224 {
   225     this->info.wm_available = 0;
   226     this->info.hw_available = 1;
   227     this->info.video_mem = 0;
   228     if (VGLCurMode == NULL) {
   229         return;
   230     }
   231     if (VGLCurMode->ModeInfo.PixelBytes > 0) {
   232         this->info.video_mem = VGLCurMode->ModeInfo.PixelBytes *
   233             VGLCurMode->ModeInfo.Xsize * VGLCurMode->ModeInfo.Ysize;
   234     }
   235 }
   236 
   237 int
   238 VGL_VideoInit(_THIS, SDL_PixelFormat * vformat)
   239 {
   240     int i;
   241     int total_modes;
   242     VGLMode **modes;
   243 
   244     /* Initialize all variables that we clean on shutdown */
   245     for (i = 0; i < NUM_MODELISTS; ++i) {
   246         SDL_nummodes[i] = 0;
   247         SDL_modelist[i] = NULL;
   248     }
   249 
   250     /* Enable mouse and keyboard support */
   251     if (SDL_getenv("SDL_NO_RAWKBD") == NULL) {
   252         if (VGLKeyboardInit(VGL_CODEKEYS) != 0) {
   253             SDL_SetError("Unable to initialize keyboard");
   254             return -1;
   255         }
   256     } else {
   257         warnx("Requiest to put keyboard into a raw mode ignored");
   258     }
   259     if (VGL_initkeymaps(STDIN_FILENO) != 0) {
   260         SDL_SetError("Unable to initialize keymap");
   261         return -1;
   262     }
   263     if (VGL_initmouse(STDIN_FILENO) != 0) {
   264         SDL_SetError("Unable to initialize mouse");
   265         return -1;
   266     }
   267 
   268     /* Determine the current screen size */
   269     if (VGLCurMode != NULL) {
   270         this->info.current_w = VGLCurMode->ModeInfo.Xsize;
   271         this->info.current_h = VGLCurMode->ModeInfo.Ysize;
   272     }
   273 
   274     /* Determine the screen depth */
   275     if (VGLCurMode != NULL)
   276         vformat->BitsPerPixel = VGLCurMode->Depth;
   277     else
   278         vformat->BitsPerPixel = 16;     /* Good default */
   279 
   280     /* Query for the list of available video modes */
   281     total_modes = 0;
   282     modes = VGLListModes(-1, V_INFO_MM_DIRECT | V_INFO_MM_PACKED);
   283     for (i = 0; modes[i] != NULL; i++) {
   284         if ((modes[i]->ModeInfo.Type == VIDBUF8) ||
   285             (modes[i]->ModeInfo.Type == VIDBUF16) ||
   286             (modes[i]->ModeInfo.Type == VIDBUF32)) {
   287             VGL_AddMode(this, modes[i]);
   288             total_modes++;
   289         }
   290     }
   291     if (total_modes == 0) {
   292         SDL_SetError("No linear video modes available");
   293         return -1;
   294     }
   295 
   296     /* Fill in our hardware acceleration capabilities */
   297     VGL_UpdateVideoInfo(this);
   298 
   299     /* Create the hardware surface lock mutex */
   300     hw_lock = SDL_CreateMutex();
   301     if (hw_lock == NULL) {
   302         SDL_SetError("Unable to create lock mutex");
   303         VGL_VideoQuit(this);
   304         return -1;
   305     }
   306 
   307     /* We're done! */
   308     return 0;
   309 }
   310 
   311 SDL_Rect **
   312 VGL_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags)
   313 {
   314     return SDL_modelist[((format->BitsPerPixel + 7) / 8) - 1];
   315 }
   316 
   317 /* Various screen update functions available */
   318 static void VGL_DirectUpdate(_THIS, int numrects, SDL_Rect * rects);
   319 static void VGL_BankedUpdate(_THIS, int numrects, SDL_Rect * rects);
   320 
   321 SDL_Surface *
   322 VGL_SetVideoMode(_THIS, SDL_Surface * current,
   323                  int width, int height, int bpp, Uint32 flags)
   324 {
   325     int mode_found;
   326     int i;
   327     VGLMode **modes;
   328 
   329     modes = VGLListModes(bpp, V_INFO_MM_DIRECT | V_INFO_MM_PACKED);
   330     mode_found = 0;
   331     for (i = 0; modes[i] != NULL; i++) {
   332         if ((modes[i]->ModeInfo.Xsize == width) &&
   333             (modes[i]->ModeInfo.Ysize == height) &&
   334             ((modes[i]->ModeInfo.Type == VIDBUF8) ||
   335              (modes[i]->ModeInfo.Type == VIDBUF16) ||
   336              (modes[i]->ModeInfo.Type == VIDBUF32))) {
   337             mode_found = 1;
   338             break;
   339         }
   340     }
   341     if (mode_found == 0) {
   342         SDL_SetError("No matching video mode found");
   343         return NULL;
   344     }
   345 
   346     /* Shutdown previous videomode (if any) */
   347     if (VGLCurMode != NULL)
   348         VGLEnd();
   349 
   350     /* Try to set the requested linear video mode */
   351     if (VGLInit(modes[i]->ModeId) != 0) {
   352         SDL_SetError("Unable to switch to requested mode");
   353         return NULL;
   354     }
   355 
   356     VGLCurMode = SDL_realloc(VGLCurMode, sizeof(VGLMode));
   357     VGLCurMode->ModeInfo = *VGLDisplay;
   358     VGLCurMode->Depth = modes[i]->Depth;
   359     VGLCurMode->ModeId = modes[i]->ModeId;
   360     VGLCurMode->Rmask = modes[i]->Rmask;
   361     VGLCurMode->Gmask = modes[i]->Gmask;
   362     VGLCurMode->Bmask = modes[i]->Bmask;
   363 
   364     /* Workaround a bug in libvgl */
   365     if (VGLCurMode->ModeInfo.PixelBytes == 0)
   366         (VGLCurMode->ModeInfo.PixelBytes = 1);
   367 
   368     current->w = VGLCurMode->ModeInfo.Xsize;
   369     current->h = VGLCurMode->ModeInfo.Ysize;
   370     current->pixels = VGLCurMode->ModeInfo.Bitmap;
   371     current->pitch = VGLCurMode->ModeInfo.Xsize *
   372         VGLCurMode->ModeInfo.PixelBytes;
   373     current->flags = (SDL_FULLSCREEN | SDL_HWSURFACE);
   374 
   375     /* Check if we are in a pseudo-color mode */
   376     if (VGLCurMode->ModeInfo.Type == VIDBUF8)
   377         current->flags |= SDL_HWPALETTE;
   378 
   379     /* Check if we can do doublebuffering */
   380     if (flags & SDL_DOUBLEBUF) {
   381         if (VGLCurMode->ModeInfo.Xsize * 2 <= VGLCurMode->ModeInfo.VYsize) {
   382             current->flags |= SDL_DOUBLEBUF;
   383             flip_page = 0;
   384             flip_address[0] = (byte *) current->pixels;
   385             flip_address[1] = (byte *) current->pixels +
   386                 current->h * current->pitch;
   387             VGL_FlipHWSurface(this, current);
   388         }
   389     }
   390 
   391     if (!SDL_ReallocFormat(current, modes[i]->Depth, VGLCurMode->Rmask,
   392                            VGLCurMode->Gmask, VGLCurMode->Bmask, 0)) {
   393         return NULL;
   394     }
   395 
   396     /* Update hardware acceleration info */
   397     VGL_UpdateVideoInfo(this);
   398 
   399     /* Set the blit function */
   400     this->UpdateRects = VGL_DirectUpdate;
   401 
   402     /* We're done */
   403     return current;
   404 }
   405 
   406 /* We don't actually allow hardware surfaces other than the main one */
   407 static int
   408 VGL_AllocHWSurface(_THIS, SDL_Surface * surface)
   409 {
   410     return -1;
   411 }
   412 static void
   413 VGL_FreeHWSurface(_THIS, SDL_Surface * surface)
   414 {
   415     return;
   416 }
   417 
   418 /* We need to wait for vertical retrace on page flipped displays */
   419 static int
   420 VGL_LockHWSurface(_THIS, SDL_Surface * surface)
   421 {
   422     if (surface == SDL_VideoSurface) {
   423         SDL_mutexP(hw_lock);
   424     }
   425     return 0;
   426 }
   427 static void
   428 VGL_UnlockHWSurface(_THIS, SDL_Surface * surface)
   429 {
   430     if (surface == SDL_VideoSurface) {
   431         SDL_mutexV(hw_lock);
   432     }
   433 }
   434 
   435 static int
   436 VGL_FlipHWSurface(_THIS, SDL_Surface * surface)
   437 {
   438 //      VGLWaitRetrace();
   439     if (VGLPanScreen(VGLDisplay, 0, flip_page * surface->h) < 0) {
   440         SDL_SetError("VGLPanSreen() failed");
   441         return -1;
   442     }
   443 
   444     flip_page = !flip_page;
   445     surface->pixels = flip_address[flip_page];
   446 
   447     return 0;
   448 }
   449 
   450 static void
   451 VGL_DirectUpdate(_THIS, int numrects, SDL_Rect * rects)
   452 {
   453     return;
   454 }
   455 
   456 static void
   457 VGL_BankedUpdate(_THIS, int numrects, SDL_Rect * rects)
   458 {
   459     return;
   460 }
   461 
   462 int
   463 VGL_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors)
   464 {
   465     int i;
   466 
   467     for (i = 0; i < ncolors; i++) {
   468         VGLSetPaletteIndex(firstcolor + i,
   469                            colors[i].r >> 2,
   470                            colors[i].g >> 2, colors[i].b >> 2);
   471     }
   472     return 1;
   473 }
   474 
   475 /* Note:  If we are terminated, this could be called in the middle of
   476    another SDL video routine -- notably UpdateRects.
   477 */
   478 void
   479 VGL_VideoQuit(_THIS)
   480 {
   481     int i, j;
   482 
   483     /* Return the keyboard to the normal state */
   484     VGLKeyboardEnd();
   485 
   486     /* Reset the console video mode if we actually initialised one */
   487     if (VGLCurMode != NULL) {
   488         VGLEnd();
   489         SDL_free(VGLCurMode);
   490         VGLCurMode = NULL;
   491     }
   492 
   493     /* Clear the lock mutex */
   494     if (hw_lock != NULL) {
   495         SDL_DestroyMutex(hw_lock);
   496         hw_lock = NULL;
   497     }
   498 
   499     /* Free video mode lists */
   500     for (i = 0; i < NUM_MODELISTS; i++) {
   501         if (SDL_modelist[i] != NULL) {
   502             for (j = 0; SDL_modelist[i][j] != NULL; ++j) {
   503                 SDL_free(SDL_modelist[i][j]);
   504             }
   505             SDL_free(SDL_modelist[i]);
   506             SDL_modelist[i] = NULL;
   507         }
   508     }
   509 
   510     if (this->screen && (this->screen->flags & SDL_HWSURFACE)) {
   511         /* Direct screen access, not a memory buffer */
   512         this->screen->pixels = NULL;
   513     }
   514 }
   515 
   516 #define VGL_RED_INDEX	0
   517 #define VGL_GREEN_INDEX	1
   518 #define VGL_BLUE_INDEX	2
   519 
   520 static VGLMode **
   521 VGLListModes(int depth, int mem_model)
   522 {
   523     static VGLMode **modes = NULL;
   524 
   525     VGLBitmap *vminfop;
   526     VGLMode **modesp, *modescp;
   527     video_info_t minfo;
   528     int adptype, i, modenum;
   529 
   530     if (modes == NULL) {
   531         modes = SDL_malloc(sizeof(VGLMode *) * M_VESA_MODE_MAX);
   532         bzero(modes, sizeof(VGLMode *) * M_VESA_MODE_MAX);
   533     }
   534     modesp = modes;
   535 
   536     for (modenum = 0; modenum < M_VESA_MODE_MAX; modenum++) {
   537         minfo.vi_mode = modenum;
   538         if (ioctl(0, CONS_MODEINFO, &minfo)
   539             || ioctl(0, CONS_CURRENT, &adptype))
   540             continue;
   541         if (minfo.vi_mode != modenum)
   542             continue;
   543         if ((minfo.vi_flags & V_INFO_GRAPHICS) == 0)
   544             continue;
   545         if ((mem_model != -1) && ((minfo.vi_mem_model & mem_model) == 0))
   546             continue;
   547         if ((depth > 1) && (minfo.vi_depth != depth))
   548             continue;
   549 
   550         /* reallocf can fail */
   551         if ((*modesp = reallocf(*modesp, sizeof(VGLMode))) == NULL)
   552             return NULL;
   553         modescp = *modesp;
   554 
   555         vminfop = &(modescp->ModeInfo);
   556         bzero(vminfop, sizeof(VGLBitmap));
   557 
   558         vminfop->Type = NOBUF;
   559 
   560         vminfop->PixelBytes = 1;        /* Good default value */
   561         switch (minfo.vi_mem_model) {
   562         case V_INFO_MM_PLANAR:
   563             /* we can handle EGA/VGA planar modes only */
   564             if (!(minfo.vi_depth != 4 || minfo.vi_planes != 4
   565                   || (adptype != KD_EGA && adptype != KD_VGA)))
   566                 vminfop->Type = VIDBUF4;
   567             break;
   568         case V_INFO_MM_PACKED:
   569             /* we can do only 256 color packed modes */
   570             if (minfo.vi_depth == 8)
   571                 vminfop->Type = VIDBUF8;
   572             break;
   573         case V_INFO_MM_VGAX:
   574             vminfop->Type = VIDBUF8X;
   575             break;
   576 #if defined(__FREEBSD__) && (defined(__DragonFly__) || __FreeBSD_version >= 500000)
   577         case V_INFO_MM_DIRECT:
   578             vminfop->PixelBytes = minfo.vi_pixel_size;
   579             switch (vminfop->PixelBytes) {
   580             case 2:
   581                 vminfop->Type = VIDBUF16;
   582                 break;
   583 #if notyet
   584             case 3:
   585                 vminfop->Type = VIDBUF24;
   586                 break;
   587 #endif
   588             case 4:
   589                 vminfop->Type = VIDBUF32;
   590                 break;
   591             default:
   592                 break;
   593             }
   594 #endif
   595         default:
   596             break;
   597         }
   598         if (vminfop->Type == NOBUF)
   599             continue;
   600 
   601         switch (vminfop->Type) {
   602         case VIDBUF16:
   603         case VIDBUF32:
   604             modescp->Rmask =
   605                 ((1 << minfo.vi_pixel_fsizes[VGL_RED_INDEX]) -
   606                  1) << minfo.vi_pixel_fields[VGL_RED_INDEX];
   607             modescp->Gmask =
   608                 ((1 << minfo.vi_pixel_fsizes[VGL_GREEN_INDEX]) -
   609                  1) << minfo.vi_pixel_fields[VGL_GREEN_INDEX];
   610             modescp->Bmask =
   611                 ((1 << minfo.vi_pixel_fsizes[VGL_BLUE_INDEX]) -
   612                  1) << minfo.vi_pixel_fields[VGL_BLUE_INDEX];
   613             break;
   614 
   615         default:
   616             break;
   617         }
   618 
   619         vminfop->Xsize = minfo.vi_width;
   620         vminfop->Ysize = minfo.vi_height;
   621         modescp->Depth = minfo.vi_depth;
   622 
   623         /* XXX */
   624         if (minfo.vi_mode >= M_VESA_BASE)
   625             modescp->ModeId = _IO('V', minfo.vi_mode - M_VESA_BASE);
   626         else
   627             modescp->ModeId = _IO('S', minfo.vi_mode);
   628 
   629         /* Sort list */
   630         for (i = 0; modes + i < modesp; i++) {
   631             if (modes[i]->ModeInfo.Xsize * modes[i]->ModeInfo.Ysize >
   632                 vminfop->Xsize * modes[i]->ModeInfo.Ysize)
   633                 continue;
   634             if ((modes[i]->ModeInfo.Xsize * modes[i]->ModeInfo.Ysize ==
   635                  vminfop->Xsize * vminfop->Ysize) &&
   636                 (modes[i]->Depth >= modescp->Depth))
   637                 continue;
   638             *modesp = modes[i];
   639             modes[i] = modescp;
   640             modescp = *modesp;
   641             vminfop = &(modescp->ModeInfo);
   642         }
   643 
   644         modesp++;
   645     }
   646 
   647     if (*modesp != NULL) {
   648         SDL_free(*modesp);
   649         *modesp = NULL;
   650     }
   651 
   652     return modes;
   653 }
   654 
   655 static void
   656 VGLWaitRetrace(void)
   657 {
   658     while (!(inb(0x3DA) & 8));
   659     while (inb(0x3DA) & 8);
   660 }
   661 
   662 /* vi: set ts=4 sw=4 expandtab: */