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