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