0
|
1 /*
|
|
2 SDL - Simple DirectMedia Layer
|
|
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
|
|
4
|
|
5 This library is free software; you can redistribute it and/or
|
|
6 modify it under the terms of the GNU Library General Public
|
|
7 License as published by the Free Software Foundation; either
|
|
8 version 2 of the License, or (at your option) any later version.
|
|
9
|
|
10 This library is distributed in the hope that it will be useful,
|
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13 Library General Public License for more details.
|
|
14
|
|
15 You should have received a copy of the GNU Library General Public
|
|
16 License along with this library; if not, write to the Free
|
|
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
18
|
|
19 Sam Lantinga
|
|
20 slouken@devolution.com
|
|
21 */
|
|
22
|
|
23 #ifdef SAVE_RCSID
|
|
24 static char rcsid =
|
|
25 "@(#) $Id$";
|
|
26 #endif
|
|
27
|
|
28 /* Framebuffer console based SDL video driver implementation.
|
|
29 */
|
|
30
|
|
31 #include <stdlib.h>
|
|
32 #include <stdio.h>
|
|
33 #include <string.h>
|
|
34 #include <fcntl.h>
|
|
35 #include <unistd.h>
|
|
36 #include <sys/ioctl.h>
|
|
37 #include <sys/mman.h>
|
|
38 #include <asm/page.h> /* For definition of PAGE_SIZE */
|
|
39
|
|
40 #include "SDL.h"
|
|
41 #include "SDL_error.h"
|
|
42 #include "SDL_video.h"
|
|
43 #include "SDL_mouse.h"
|
|
44 #include "SDL_sysvideo.h"
|
|
45 #include "SDL_pixels_c.h"
|
|
46 #include "SDL_events_c.h"
|
|
47 #include "SDL_fbvideo.h"
|
|
48 #include "SDL_fbmouse_c.h"
|
|
49 #include "SDL_fbevents_c.h"
|
|
50 #include "SDL_fb3dfx.h"
|
|
51 #include "SDL_fbmatrox.h"
|
|
52
|
|
53 #if defined(i386) && defined(FB_TYPE_VGA_PLANES)
|
|
54 #define VGA16_FBCON_SUPPORT
|
|
55 #ifndef FB_AUX_VGA_PLANES_VGA4
|
|
56 #define FB_AUX_VGA_PLANES_VGA4 0
|
|
57 #endif
|
|
58 static inline void outb (unsigned char value, unsigned short port)
|
|
59 {
|
|
60 __asm__ __volatile__ ("outb %b0,%w1"::"a" (value), "Nd" (port));
|
|
61 }
|
|
62 #endif /* FB_TYPE_VGA_PLANES */
|
|
63
|
|
64 /* A list of video resolutions that we query for (sorted largest to smallest) */
|
|
65 static SDL_Rect checkres[] = {
|
|
66 { 0, 0, 1600, 1200 }, /* 16 bpp: 0x11E, or 286 */
|
|
67 { 0, 0, 1408, 1056 }, /* 16 bpp: 0x19A, or 410 */
|
|
68 { 0, 0, 1280, 1024 }, /* 16 bpp: 0x11A, or 282 */
|
|
69 { 0, 0, 1152, 864 }, /* 16 bpp: 0x192, or 402 */
|
|
70 { 0, 0, 1024, 768 }, /* 16 bpp: 0x117, or 279 */
|
|
71 { 0, 0, 960, 720 }, /* 16 bpp: 0x18A, or 394 */
|
|
72 { 0, 0, 800, 600 }, /* 16 bpp: 0x114, or 276 */
|
|
73 { 0, 0, 768, 576 }, /* 16 bpp: 0x182, or 386 */
|
|
74 { 0, 0, 640, 480 }, /* 16 bpp: 0x111, or 273 */
|
|
75 { 0, 0, 640, 400 }, /* 8 bpp: 0x100, or 256 */
|
|
76 { 0, 0, 512, 384 },
|
|
77 { 0, 0, 320, 240 },
|
|
78 { 0, 0, 320, 200 }
|
|
79 };
|
|
80 static struct {
|
|
81 int xres;
|
|
82 int yres;
|
|
83 int pixclock;
|
|
84 int left;
|
|
85 int right;
|
|
86 int upper;
|
|
87 int lower;
|
|
88 int hslen;
|
|
89 int vslen;
|
|
90 int sync;
|
|
91 int vmode;
|
|
92 } vesa_timings[] = {
|
|
93 #ifdef USE_VESA_TIMINGS /* Only tested on Matrox Millenium I */
|
|
94 { 640, 400, 39771, 48, 16, 39, 8, 96, 2, 2, 0 }, /* 70 Hz */
|
|
95 { 640, 480, 39683, 48, 16, 33, 10, 96, 2, 0, 0 }, /* 60 Hz */
|
|
96 { 768, 576, 26101, 144, 16, 28, 6, 112, 4, 0, 0 }, /* 60 Hz */
|
|
97 { 800, 600, 24038, 144, 24, 28, 8, 112, 6, 0, 0 }, /* 60 Hz */
|
|
98 { 960, 720, 17686, 144, 24, 28, 8, 112, 4, 0, 0 }, /* 60 Hz */
|
|
99 { 1024, 768, 15386, 160, 32, 30, 4, 128, 4, 0, 0 }, /* 60 Hz */
|
|
100 { 1152, 864, 12286, 192, 32, 30, 4, 128, 4, 0, 0 }, /* 60 Hz */
|
|
101 { 1280, 1024, 9369, 224, 32, 32, 4, 136, 4, 0, 0 }, /* 60 Hz */
|
|
102 { 1408, 1056, 8214, 256, 40, 32, 5, 144, 5, 0, 0 }, /* 60 Hz */
|
|
103 { 1600, 1200,/*?*/0, 272, 48, 32, 5, 152, 5, 0, 0 }, /* 60 Hz */
|
|
104 #else
|
|
105 /* You can generate these timings from your XF86Config file using
|
|
106 the 'modeline2fb' perl script included with the fbset package.
|
|
107 These timings were generated for Matrox Millenium I, 15" monitor.
|
|
108 */
|
|
109 { 320, 200, 79440, 16, 16, 20, 4, 48, 1, 0, 2 }, /* 70 Hz */
|
|
110 { 320, 240, 63492, 16, 16, 16, 4, 48, 2, 0, 2 }, /* 72 Hz */
|
|
111 { 512, 384, 49603, 48, 16, 16, 1, 64, 3, 0, 0 }, /* 78 Hz */
|
|
112 { 640, 400, 31746, 96, 32, 41, 1, 64, 3, 2, 0 }, /* 85 Hz */
|
|
113 { 640, 480, 31746, 120, 16, 16, 1, 64, 3, 0, 0 }, /* 75 Hz */
|
|
114 { 768, 576, 26101, 144, 16, 28, 6, 112, 4, 0, 0 }, /* 60 Hz */
|
|
115 { 800, 600, 20000, 64, 56, 23, 37, 120, 6, 3, 0 }, /* 72 Hz */
|
|
116 { 960, 720, 17686, 144, 24, 28, 8, 112, 4, 0, 0 }, /* 60 Hz */
|
|
117 { 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0, 0 }, /* 70 Hz */
|
|
118 { 1152, 864, 12286, 192, 32, 30, 4, 128, 4, 0, 0 }, /* 60 Hz */
|
|
119 { 1280, 1024, 9369, 224, 32, 32, 4, 136, 4, 0, 0 }, /* 60 Hz */
|
|
120 { 1408, 1056, 8214, 256, 40, 32, 5, 144, 5, 0, 0 }, /* 60 Hz */
|
|
121 { 1600, 1200,/*?*/0, 272, 48, 32, 5, 152, 5, 0, 0 }, /* 60 Hz */
|
|
122 #endif
|
|
123 };
|
|
124
|
|
125 /* Initialization/Query functions */
|
|
126 static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat);
|
|
127 static SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
|
|
128 static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
|
|
129 #ifdef VGA16_FBCON_SUPPORT
|
|
130 static SDL_Surface *FB_SetVGA16Mode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
|
|
131 #endif
|
|
132 static int FB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
|
|
133 static void FB_VideoQuit(_THIS);
|
|
134
|
|
135 /* Hardware surface functions */
|
|
136 static int FB_InitHWSurfaces(_THIS, char *base, int size);
|
|
137 static void FB_FreeHWSurfaces(_THIS);
|
|
138 static int FB_AllocHWSurface(_THIS, SDL_Surface *surface);
|
|
139 static int FB_LockHWSurface(_THIS, SDL_Surface *surface);
|
|
140 static void FB_UnlockHWSurface(_THIS, SDL_Surface *surface);
|
|
141 static void FB_FreeHWSurface(_THIS, SDL_Surface *surface);
|
|
142 static void FB_WaitVBL(_THIS);
|
|
143 static int FB_FlipHWSurface(_THIS, SDL_Surface *surface);
|
|
144
|
|
145 /* Internal palette functions */
|
|
146 static void FB_SavePalette(_THIS, struct fb_fix_screeninfo *finfo,
|
|
147 struct fb_var_screeninfo *vinfo);
|
|
148 static void FB_RestorePalette(_THIS);
|
|
149
|
|
150 /* FB driver bootstrap functions */
|
|
151
|
|
152 static int FB_Available(void)
|
|
153 {
|
|
154 int console;
|
|
155 const char *SDL_fbdev;
|
|
156
|
|
157 SDL_fbdev = getenv("SDL_FBDEV");
|
|
158 if ( SDL_fbdev == NULL ) {
|
|
159 SDL_fbdev = "/dev/fb0";
|
|
160 }
|
|
161 console = open(SDL_fbdev, O_RDWR, 0);
|
|
162 if ( console >= 0 ) {
|
|
163 close(console);
|
|
164 }
|
|
165 return(console >= 0);
|
|
166 }
|
|
167
|
|
168 static void FB_DeleteDevice(SDL_VideoDevice *device)
|
|
169 {
|
|
170 free(device->hidden);
|
|
171 free(device);
|
|
172 }
|
|
173
|
|
174 static SDL_VideoDevice *FB_CreateDevice(int devindex)
|
|
175 {
|
|
176 SDL_VideoDevice *this;
|
|
177
|
|
178 /* Initialize all variables that we clean on shutdown */
|
|
179 this = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
|
|
180 if ( this ) {
|
|
181 memset(this, 0, (sizeof *this));
|
|
182 this->hidden = (struct SDL_PrivateVideoData *)
|
|
183 malloc((sizeof *this->hidden));
|
|
184 }
|
|
185 if ( (this == NULL) || (this->hidden == NULL) ) {
|
|
186 SDL_OutOfMemory();
|
|
187 if ( this ) {
|
|
188 free(this);
|
|
189 }
|
|
190 return(0);
|
|
191 }
|
|
192 memset(this->hidden, 0, (sizeof *this->hidden));
|
|
193 wait_vbl = FB_WaitVBL;
|
|
194 mouse_fd = -1;
|
|
195 keyboard_fd = -1;
|
|
196
|
|
197 /* Set the function pointers */
|
|
198 this->VideoInit = FB_VideoInit;
|
|
199 this->ListModes = FB_ListModes;
|
|
200 this->SetVideoMode = FB_SetVideoMode;
|
|
201 this->SetColors = FB_SetColors;
|
|
202 this->UpdateRects = NULL;
|
|
203 this->VideoQuit = FB_VideoQuit;
|
|
204 this->AllocHWSurface = FB_AllocHWSurface;
|
|
205 this->CheckHWBlit = NULL;
|
|
206 this->FillHWRect = NULL;
|
|
207 this->SetHWColorKey = NULL;
|
|
208 this->SetHWAlpha = NULL;
|
|
209 this->LockHWSurface = FB_LockHWSurface;
|
|
210 this->UnlockHWSurface = FB_UnlockHWSurface;
|
|
211 this->FlipHWSurface = FB_FlipHWSurface;
|
|
212 this->FreeHWSurface = FB_FreeHWSurface;
|
|
213 this->SetCaption = NULL;
|
|
214 this->SetIcon = NULL;
|
|
215 this->IconifyWindow = NULL;
|
|
216 this->GrabInput = NULL;
|
|
217 this->GetWMInfo = NULL;
|
|
218 this->InitOSKeymap = FB_InitOSKeymap;
|
|
219 this->PumpEvents = FB_PumpEvents;
|
|
220
|
|
221 this->free = FB_DeleteDevice;
|
|
222
|
|
223 return this;
|
|
224 }
|
|
225
|
|
226 VideoBootStrap FBCON_bootstrap = {
|
|
227 "fbcon", "Linux Framebuffer Console",
|
|
228 FB_Available, FB_CreateDevice
|
|
229 };
|
|
230
|
|
231 static int FB_CheckMode(_THIS, struct fb_var_screeninfo *vinfo,
|
|
232 int index, unsigned int *w, unsigned int *h)
|
|
233 {
|
|
234 int mode_okay;
|
|
235
|
|
236 mode_okay = 0;
|
|
237 vinfo->bits_per_pixel = (index+1)*8;
|
|
238 vinfo->xres = *w;
|
|
239 vinfo->xres_virtual = *w;
|
|
240 vinfo->yres = *h;
|
|
241 vinfo->yres_virtual = *h;
|
|
242 vinfo->activate = FB_ACTIVATE_TEST;
|
|
243 if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, vinfo) == 0 ) {
|
|
244 #ifdef FBCON_DEBUG
|
|
245 fprintf(stderr, "Checked mode %dx%d at %d bpp, got mode %dx%d at %d bpp\n", *w, *h, (index+1)*8, vinfo->xres, vinfo->yres, vinfo->bits_per_pixel);
|
|
246 #endif
|
|
247 if ( (((vinfo->bits_per_pixel+7)/8)-1) == index ) {
|
|
248 *w = vinfo->xres;
|
|
249 *h = vinfo->yres;
|
|
250 mode_okay = 1;
|
|
251 }
|
|
252 }
|
|
253 return mode_okay;
|
|
254 }
|
|
255
|
|
256 static int FB_AddMode(_THIS, int index, unsigned int w, unsigned int h)
|
|
257 {
|
|
258 SDL_Rect *mode;
|
|
259 int i;
|
|
260 int next_mode;
|
|
261
|
|
262 /* Check to see if we already have this mode */
|
|
263 if ( SDL_nummodes[index] > 0 ) {
|
|
264 mode = SDL_modelist[index][SDL_nummodes[index]-1];
|
|
265 if ( (mode->w == w) && (mode->h == h) ) {
|
|
266 #ifdef FBCON_DEBUG
|
|
267 fprintf(stderr, "We already have mode %dx%d at %d bytes per pixel\n", w, h, index+1);
|
|
268 #endif
|
|
269 return(0);
|
|
270 }
|
|
271 }
|
|
272
|
|
273 /* Only allow a mode if we have a valid timing for it */
|
|
274 next_mode = 0;
|
|
275 for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) {
|
|
276 if ( (w == vesa_timings[i].xres) &&
|
|
277 (h == vesa_timings[i].yres) && vesa_timings[i].pixclock ) {
|
|
278 next_mode = i;
|
|
279 break;
|
|
280 }
|
|
281 }
|
|
282 if ( ! next_mode ) {
|
|
283 #ifdef FBCON_DEBUG
|
|
284 fprintf(stderr, "No valid timing line for mode %dx%d\n", w, h);
|
|
285 #endif
|
|
286 return(0);
|
|
287 }
|
|
288
|
|
289 /* Set up the new video mode rectangle */
|
|
290 mode = (SDL_Rect *)malloc(sizeof *mode);
|
|
291 if ( mode == NULL ) {
|
|
292 SDL_OutOfMemory();
|
|
293 return(-1);
|
|
294 }
|
|
295 mode->x = 0;
|
|
296 mode->y = 0;
|
|
297 mode->w = w;
|
|
298 mode->h = h;
|
|
299 #ifdef FBCON_DEBUG
|
|
300 fprintf(stderr, "Adding mode %dx%d at %d bytes per pixel\n", w, h, index+1);
|
|
301 #endif
|
|
302
|
|
303 /* Allocate the new list of modes, and fill in the new mode */
|
|
304 next_mode = SDL_nummodes[index];
|
|
305 SDL_modelist[index] = (SDL_Rect **)
|
|
306 realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
|
|
307 if ( SDL_modelist[index] == NULL ) {
|
|
308 SDL_OutOfMemory();
|
|
309 SDL_nummodes[index] = 0;
|
|
310 free(mode);
|
|
311 return(-1);
|
|
312 }
|
|
313 SDL_modelist[index][next_mode] = mode;
|
|
314 SDL_modelist[index][next_mode+1] = NULL;
|
|
315 SDL_nummodes[index]++;
|
|
316
|
|
317 return(0);
|
|
318 }
|
|
319
|
|
320 static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat)
|
|
321 {
|
|
322 struct fb_fix_screeninfo finfo;
|
|
323 struct fb_var_screeninfo vinfo;
|
|
324 int i, j;
|
|
325 int current_index;
|
|
326 unsigned int current_w;
|
|
327 unsigned int current_h;
|
|
328 const char *SDL_fbdev;
|
|
329
|
|
330 /* Initialize the library */
|
|
331 SDL_fbdev = getenv("SDL_FBDEV");
|
|
332 if ( SDL_fbdev == NULL ) {
|
|
333 SDL_fbdev = "/dev/fb0";
|
|
334 }
|
|
335 console_fd = open(SDL_fbdev, O_RDWR, 0);
|
|
336 if ( console_fd < 0 ) {
|
|
337 SDL_SetError("Unable to open %s", SDL_fbdev);
|
|
338 return(-1);
|
|
339 }
|
|
340
|
|
341 #ifndef DISABLE_THREADS
|
|
342 /* Create the hardware surface lock mutex */
|
|
343 hw_lock = SDL_CreateMutex();
|
|
344 if ( hw_lock == NULL ) {
|
|
345 SDL_SetError("Unable to create lock mutex");
|
|
346 FB_VideoQuit(this);
|
|
347 return(-1);
|
|
348 }
|
|
349 #endif
|
|
350
|
|
351 /* Get the type of video hardware */
|
|
352 if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
|
|
353 SDL_SetError("Couldn't get console hardware info");
|
|
354 FB_VideoQuit(this);
|
|
355 return(-1);
|
|
356 }
|
|
357 switch (finfo.type) {
|
|
358 case FB_TYPE_PACKED_PIXELS:
|
|
359 /* Supported, no worries.. */
|
|
360 break;
|
|
361 #ifdef VGA16_FBCON_SUPPORT
|
|
362 case FB_TYPE_VGA_PLANES:
|
|
363 /* VGA16 is supported, but that's it */
|
|
364 if ( finfo.type_aux == FB_AUX_VGA_PLANES_VGA4 ) {
|
|
365 if ( ioperm(0x3b4, 0x3df - 0x3b4 + 1, 1) < 0 ) {
|
|
366 SDL_SetError("No I/O port permissions");
|
|
367 FB_VideoQuit(this);
|
|
368 return(-1);
|
|
369 }
|
|
370 this->SetVideoMode = FB_SetVGA16Mode;
|
|
371 break;
|
|
372 }
|
|
373 /* Fall through to unsupported case */
|
|
374 #endif /* VGA16_FBCON_SUPPORT */
|
|
375 default:
|
|
376 SDL_SetError("Unsupported console hardware");
|
|
377 FB_VideoQuit(this);
|
|
378 return(-1);
|
|
379 }
|
|
380 switch (finfo.visual) {
|
|
381 case FB_VISUAL_TRUECOLOR:
|
|
382 case FB_VISUAL_PSEUDOCOLOR:
|
|
383 case FB_VISUAL_STATIC_PSEUDOCOLOR:
|
|
384 case FB_VISUAL_DIRECTCOLOR:
|
|
385 break;
|
|
386 default:
|
|
387 SDL_SetError("Unsupported console hardware");
|
|
388 FB_VideoQuit(this);
|
|
389 return(-1);
|
|
390 }
|
|
391
|
|
392 /* Check if the user wants to disable hardware acceleration */
|
|
393 { const char *fb_accel;
|
|
394 fb_accel = getenv("SDL_FBACCEL");
|
|
395 if ( fb_accel ) {
|
|
396 finfo.accel = atoi(fb_accel);
|
|
397 }
|
|
398 }
|
|
399
|
|
400 /* Memory map the device, compensating for buggy PPC mmap() */
|
|
401 mapped_offset = (((long)finfo.smem_start) -
|
|
402 (((long)finfo.smem_start)&~(PAGE_SIZE-1)));
|
|
403 mapped_memlen = finfo.smem_len+mapped_offset;
|
|
404 mapped_mem = mmap(NULL, mapped_memlen,
|
|
405 PROT_READ|PROT_WRITE, MAP_SHARED, console_fd, 0);
|
|
406 if ( mapped_mem == (char *)-1 ) {
|
|
407 SDL_SetError("Unable to memory map the video hardware");
|
|
408 mapped_mem = NULL;
|
|
409 FB_VideoQuit(this);
|
|
410 return(-1);
|
|
411 }
|
|
412
|
|
413 /* Determine the current screen depth */
|
|
414 if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
|
|
415 SDL_SetError("Couldn't get console pixel format");
|
|
416 FB_VideoQuit(this);
|
|
417 return(-1);
|
|
418 }
|
|
419 vformat->BitsPerPixel = vinfo.bits_per_pixel;
|
|
420 if ( vformat->BitsPerPixel < 8 ) {
|
|
421 /* Assuming VGA16, we handle this via a shadow framebuffer */
|
|
422 vformat->BitsPerPixel = 8;
|
|
423 }
|
|
424 for ( i=0; i<vinfo.red.length; ++i ) {
|
|
425 vformat->Rmask <<= 1;
|
|
426 vformat->Rmask |= (0x00000001<<vinfo.red.offset);
|
|
427 }
|
|
428 for ( i=0; i<vinfo.green.length; ++i ) {
|
|
429 vformat->Gmask <<= 1;
|
|
430 vformat->Gmask |= (0x00000001<<vinfo.green.offset);
|
|
431 }
|
|
432 for ( i=0; i<vinfo.blue.length; ++i ) {
|
|
433 vformat->Bmask <<= 1;
|
|
434 vformat->Bmask |= (0x00000001<<vinfo.blue.offset);
|
|
435 }
|
|
436 saved_vinfo = vinfo;
|
|
437
|
|
438 /* Save hardware palette, if needed */
|
|
439 FB_SavePalette(this, &finfo, &vinfo);
|
|
440
|
|
441 /* If the I/O registers are available, memory map them so we
|
|
442 can take advantage of any supported hardware acceleration.
|
|
443 */
|
|
444 vinfo.accel_flags = 0; /* Temporarily reserve registers */
|
|
445 ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo);
|
|
446 if ( finfo.accel && finfo.mmio_len ) {
|
|
447 mapped_iolen = finfo.mmio_len;
|
|
448 mapped_io = mmap(NULL, mapped_iolen, PROT_READ|PROT_WRITE,
|
|
449 MAP_SHARED, console_fd, mapped_memlen);
|
|
450 if ( mapped_io == (char *)-1 ) {
|
|
451 /* Hmm, failed to memory map I/O registers */
|
|
452 mapped_io = NULL;
|
|
453 }
|
|
454 }
|
|
455
|
|
456 /* Query for the list of available video modes */
|
|
457 current_w = vinfo.xres;
|
|
458 current_h = vinfo.yres;
|
|
459 current_index = ((vinfo.bits_per_pixel+7)/8)-1;
|
|
460 for ( i=0; i<NUM_MODELISTS; ++i ) {
|
|
461 SDL_nummodes[i] = 0;
|
|
462 SDL_modelist[i] = NULL;
|
|
463 for ( j=0; j<(sizeof(checkres)/sizeof(checkres[0])); ++j ) {
|
|
464 unsigned int w, h;
|
|
465
|
|
466 /* See if we are querying for the current mode */
|
|
467 w = checkres[j].w;
|
|
468 h = checkres[j].h;
|
|
469 if ( i == current_index ) {
|
|
470 if ( (current_w > w) || (current_h > h) ) {
|
|
471 /* Only check once */
|
|
472 FB_AddMode(this, i,current_w,current_h);
|
|
473 current_index = -1;
|
|
474 }
|
|
475 }
|
|
476 if ( FB_CheckMode(this, &vinfo, i, &w, &h) ) {
|
|
477 FB_AddMode(this, i, w, h);
|
|
478 }
|
|
479 }
|
|
480 }
|
|
481
|
|
482 /* Fill in our hardware acceleration capabilities */
|
|
483 this->info.wm_available = 0;
|
|
484 this->info.hw_available = 1;
|
|
485 this->info.video_mem = finfo.smem_len/1024;
|
|
486 if ( mapped_io ) {
|
|
487 switch (finfo.accel) {
|
|
488 case FB_ACCEL_MATROX_MGA2064W:
|
|
489 case FB_ACCEL_MATROX_MGA1064SG:
|
|
490 case FB_ACCEL_MATROX_MGA2164W:
|
|
491 case FB_ACCEL_MATROX_MGA2164W_AGP:
|
|
492 case FB_ACCEL_MATROX_MGAG100:
|
|
493 /*case FB_ACCEL_MATROX_MGAG200: G200 acceleration broken! */
|
|
494 case FB_ACCEL_MATROX_MGAG400:
|
|
495 #ifdef FBACCEL_DEBUG
|
|
496 printf("Matrox hardware accelerator!\n");
|
|
497 #endif
|
|
498 FB_MatroxAccel(this, finfo.accel);
|
|
499 break;
|
|
500 case FB_ACCEL_3DFX_BANSHEE:
|
|
501 #ifdef FBACCEL_DEBUG
|
|
502 printf("3DFX hardware accelerator!\n");
|
|
503 #endif
|
|
504 FB_3DfxAccel(this, finfo.accel);
|
|
505 break;
|
|
506 default:
|
|
507 #ifdef FBACCEL_DEBUG
|
|
508 printf("Unknown hardware accelerator.\n");
|
|
509 #endif
|
|
510 break;
|
|
511 }
|
|
512 }
|
|
513
|
|
514 /* Enable mouse and keyboard support */
|
|
515 if ( FB_OpenKeyboard(this) < 0 ) {
|
|
516 FB_VideoQuit(this);
|
|
517 return(-1);
|
|
518 }
|
|
519 if ( FB_OpenMouse(this) < 0 ) {
|
|
520 const char *sdl_nomouse;
|
|
521
|
|
522 sdl_nomouse = getenv("SDL_NOMOUSE");
|
|
523 if ( ! sdl_nomouse ) {
|
|
524 SDL_SetError("Unable to open mouse");
|
|
525 FB_VideoQuit(this);
|
|
526 return(-1);
|
|
527 }
|
|
528 }
|
|
529
|
|
530 /* We're done! */
|
|
531 return(0);
|
|
532 }
|
|
533
|
|
534 static SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
|
|
535 {
|
|
536 return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
|
|
537 }
|
|
538
|
|
539 /* Various screen update functions available */
|
|
540 static void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
|
|
541 #ifdef VGA16_FBCON_SUPPORT
|
|
542 static void FB_VGA16Update(_THIS, int numrects, SDL_Rect *rects);
|
|
543 #endif
|
|
544
|
|
545 #ifdef FBCON_DEBUG
|
|
546 static void print_vinfo(struct fb_var_screeninfo *vinfo)
|
|
547 {
|
|
548 fprintf(stderr, "Printing vinfo:\n");
|
|
549 fprintf(stderr, "\txres: %d\n", vinfo->xres);
|
|
550 fprintf(stderr, "\tyres: %d\n", vinfo->yres);
|
|
551 fprintf(stderr, "\txres_virtual: %d\n", vinfo->xres_virtual);
|
|
552 fprintf(stderr, "\tyres_virtual: %d\n", vinfo->yres_virtual);
|
|
553 fprintf(stderr, "\txoffset: %d\n", vinfo->xoffset);
|
|
554 fprintf(stderr, "\tyoffset: %d\n", vinfo->yoffset);
|
|
555 fprintf(stderr, "\tbits_per_pixel: %d\n", vinfo->bits_per_pixel);
|
|
556 fprintf(stderr, "\tgrayscale: %d\n", vinfo->grayscale);
|
|
557 fprintf(stderr, "\tnonstd: %d\n", vinfo->nonstd);
|
|
558 fprintf(stderr, "\tactivate: %d\n", vinfo->activate);
|
|
559 fprintf(stderr, "\theight: %d\n", vinfo->height);
|
|
560 fprintf(stderr, "\twidth: %d\n", vinfo->width);
|
|
561 fprintf(stderr, "\taccel_flags: %d\n", vinfo->accel_flags);
|
|
562 fprintf(stderr, "\tpixclock: %d\n", vinfo->pixclock);
|
|
563 fprintf(stderr, "\tleft_margin: %d\n", vinfo->left_margin);
|
|
564 fprintf(stderr, "\tright_margin: %d\n", vinfo->right_margin);
|
|
565 fprintf(stderr, "\tupper_margin: %d\n", vinfo->upper_margin);
|
|
566 fprintf(stderr, "\tlower_margin: %d\n", vinfo->lower_margin);
|
|
567 fprintf(stderr, "\thsync_len: %d\n", vinfo->hsync_len);
|
|
568 fprintf(stderr, "\tvsync_len: %d\n", vinfo->vsync_len);
|
|
569 fprintf(stderr, "\tsync: %d\n", vinfo->sync);
|
|
570 fprintf(stderr, "\tvmode: %d\n", vinfo->vmode);
|
|
571 fprintf(stderr, "\tred: %d/%d\n", vinfo->red.length, vinfo->red.offset);
|
|
572 fprintf(stderr, "\tgreen: %d/%d\n", vinfo->green.length, vinfo->green.offset);
|
|
573 fprintf(stderr, "\tblue: %d/%d\n", vinfo->blue.length, vinfo->blue.offset);
|
|
574 fprintf(stderr, "\talpha: %d/%d\n", vinfo->transp.length, vinfo->transp.offset);
|
|
575 }
|
|
576 static void print_finfo(struct fb_fix_screeninfo *finfo)
|
|
577 {
|
|
578 fprintf(stderr, "Printing finfo:\n");
|
|
579 fprintf(stderr, "\tsmem_start = %p\n", (char *)finfo->smem_start);
|
|
580 fprintf(stderr, "\tsmem_len = %d\n", finfo->smem_len);
|
|
581 fprintf(stderr, "\ttype = %d\n", finfo->type);
|
|
582 fprintf(stderr, "\ttype_aux = %d\n", finfo->type_aux);
|
|
583 fprintf(stderr, "\tvisual = %d\n", finfo->visual);
|
|
584 fprintf(stderr, "\txpanstep = %d\n", finfo->xpanstep);
|
|
585 fprintf(stderr, "\typanstep = %d\n", finfo->ypanstep);
|
|
586 fprintf(stderr, "\tywrapstep = %d\n", finfo->ywrapstep);
|
|
587 fprintf(stderr, "\tline_length = %d\n", finfo->line_length);
|
|
588 fprintf(stderr, "\tmmio_start = %p\n", (char *)finfo->mmio_start);
|
|
589 fprintf(stderr, "\tmmio_len = %d\n", finfo->mmio_len);
|
|
590 fprintf(stderr, "\taccel = %d\n", finfo->accel);
|
|
591 }
|
|
592 #endif
|
|
593
|
|
594 static int choose_fbmodes_mode(struct fb_var_screeninfo *vinfo)
|
|
595 {
|
|
596 int matched;
|
|
597 FILE *fbmodes;
|
|
598
|
|
599 matched = 0;
|
|
600 fbmodes = fopen("/etc/fb.modes", "r");
|
|
601 if ( fbmodes ) {
|
|
602 /* FIXME: Parse the mode definition file */
|
|
603 fclose(fbmodes);
|
|
604 }
|
|
605 return(matched);
|
|
606 }
|
|
607
|
|
608 static int choose_vesa_mode(struct fb_var_screeninfo *vinfo)
|
|
609 {
|
|
610 int matched;
|
|
611 int i;
|
|
612
|
|
613 /* Check for VESA timings */
|
|
614 matched = 0;
|
|
615 for ( i=0; i<(sizeof(vesa_timings)/sizeof(vesa_timings[0])); ++i ) {
|
|
616 if ( (vinfo->xres == vesa_timings[i].xres) &&
|
|
617 (vinfo->yres == vesa_timings[i].yres) ) {
|
|
618 #ifdef FBCON_DEBUG
|
|
619 fprintf(stderr, "Using VESA timings for %dx%d\n",
|
|
620 vinfo->xres, vinfo->yres);
|
|
621 #endif
|
|
622 if ( vesa_timings[i].pixclock ) {
|
|
623 vinfo->pixclock = vesa_timings[i].pixclock;
|
|
624 }
|
|
625 vinfo->left_margin = vesa_timings[i].left;
|
|
626 vinfo->right_margin = vesa_timings[i].right;
|
|
627 vinfo->upper_margin = vesa_timings[i].upper;
|
|
628 vinfo->lower_margin = vesa_timings[i].lower;
|
|
629 vinfo->hsync_len = vesa_timings[i].hslen;
|
|
630 vinfo->vsync_len = vesa_timings[i].vslen;
|
|
631 vinfo->sync = vesa_timings[i].sync;
|
|
632 vinfo->vmode = vesa_timings[i].vmode;
|
|
633 matched = 1;
|
|
634 break;
|
|
635 }
|
|
636 }
|
|
637 return(matched);
|
|
638 }
|
|
639
|
|
640 #ifdef VGA16_FBCON_SUPPORT
|
|
641 static SDL_Surface *FB_SetVGA16Mode(_THIS, SDL_Surface *current,
|
|
642 int width, int height, int bpp, Uint32 flags)
|
|
643 {
|
|
644 struct fb_fix_screeninfo finfo;
|
|
645 struct fb_var_screeninfo vinfo;
|
|
646
|
|
647 /* Set the terminal into graphics mode */
|
|
648 if ( FB_EnterGraphicsMode(this) < 0 ) {
|
|
649 return(NULL);
|
|
650 }
|
|
651
|
|
652 /* Restore the original palette */
|
|
653 FB_RestorePalette(this);
|
|
654
|
|
655 /* Set the video mode and get the final screen format */
|
|
656 if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
|
|
657 SDL_SetError("Couldn't get console screen info");
|
|
658 return(NULL);
|
|
659 }
|
|
660 cache_vinfo = vinfo;
|
|
661 #ifdef FBCON_DEBUG
|
|
662 fprintf(stderr, "Printing actual vinfo:\n");
|
|
663 print_vinfo(&vinfo);
|
|
664 #endif
|
|
665 if ( ! SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) {
|
|
666 return(NULL);
|
|
667 }
|
|
668 current->format->palette->ncolors = 16;
|
|
669
|
|
670 /* Get the fixed information about the console hardware.
|
|
671 This is necessary since finfo.line_length changes.
|
|
672 */
|
|
673 if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
|
|
674 SDL_SetError("Couldn't get console hardware info");
|
|
675 return(NULL);
|
|
676 }
|
|
677 #ifdef FBCON_DEBUG
|
|
678 fprintf(stderr, "Printing actual finfo:\n");
|
|
679 print_finfo(&finfo);
|
|
680 #endif
|
|
681
|
|
682 /* Save hardware palette, if needed */
|
|
683 FB_SavePalette(this, &finfo, &vinfo);
|
|
684
|
|
685 /* Set up the new mode framebuffer */
|
|
686 current->flags = SDL_FULLSCREEN;
|
|
687 current->w = vinfo.xres;
|
|
688 current->h = vinfo.yres;
|
|
689 current->pitch = current->w;
|
|
690 current->pixels = malloc(current->h*current->pitch);
|
|
691
|
|
692 /* Set the update rectangle function */
|
|
693 this->UpdateRects = FB_VGA16Update;
|
|
694
|
|
695 /* We're done */
|
|
696 return(current);
|
|
697 }
|
|
698 #endif /* VGA16_FBCON_SUPPORT */
|
|
699
|
|
700 static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current,
|
|
701 int width, int height, int bpp, Uint32 flags)
|
|
702 {
|
|
703 struct fb_fix_screeninfo finfo;
|
|
704 struct fb_var_screeninfo vinfo;
|
|
705 int i;
|
|
706 Uint32 Rmask;
|
|
707 Uint32 Gmask;
|
|
708 Uint32 Bmask;
|
|
709 char *surfaces_mem;
|
|
710 int surfaces_len;
|
|
711
|
|
712 /* Set the terminal into graphics mode */
|
|
713 if ( FB_EnterGraphicsMode(this) < 0 ) {
|
|
714 return(NULL);
|
|
715 }
|
|
716
|
|
717 /* Restore the original palette */
|
|
718 FB_RestorePalette(this);
|
|
719
|
|
720 /* Set the video mode and get the final screen format */
|
|
721 if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
|
|
722 SDL_SetError("Couldn't get console screen info");
|
|
723 return(NULL);
|
|
724 }
|
|
725 #ifdef FBCON_DEBUG
|
|
726 fprintf(stderr, "Printing original vinfo:\n");
|
|
727 print_vinfo(&vinfo);
|
|
728 #endif
|
|
729 if ( (vinfo.xres != width) || (vinfo.yres != height) ||
|
|
730 (vinfo.bits_per_pixel != bpp) || (flags & SDL_DOUBLEBUF) ) {
|
|
731 vinfo.activate = FB_ACTIVATE_NOW;
|
|
732 vinfo.accel_flags = 0;
|
|
733 vinfo.bits_per_pixel = bpp;
|
|
734 vinfo.xres = width;
|
|
735 vinfo.xres_virtual = width;
|
|
736 vinfo.yres = height;
|
|
737 if ( flags & SDL_DOUBLEBUF ) {
|
|
738 vinfo.yres_virtual = height*2;
|
|
739 } else {
|
|
740 vinfo.yres_virtual = height;
|
|
741 }
|
|
742 vinfo.xoffset = 0;
|
|
743 vinfo.yoffset = 0;
|
|
744 vinfo.red.length = vinfo.red.offset = 0;
|
|
745 vinfo.green.length = vinfo.green.offset = 0;
|
|
746 vinfo.blue.length = vinfo.blue.offset = 0;
|
|
747 vinfo.transp.length = vinfo.transp.offset = 0;
|
|
748 if ( ! choose_fbmodes_mode(&vinfo) ) {
|
|
749 choose_vesa_mode(&vinfo);
|
|
750 }
|
|
751 #ifdef FBCON_DEBUG
|
|
752 fprintf(stderr, "Printing wanted vinfo:\n");
|
|
753 print_vinfo(&vinfo);
|
|
754 #endif
|
|
755 if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {
|
|
756 vinfo.yres_virtual = height;
|
|
757 if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {
|
|
758 SDL_SetError("Couldn't set console screen info");
|
|
759 return(NULL);
|
|
760 }
|
|
761 }
|
|
762 }
|
|
763 cache_vinfo = vinfo;
|
|
764 #ifdef FBCON_DEBUG
|
|
765 fprintf(stderr, "Printing actual vinfo:\n");
|
|
766 print_vinfo(&vinfo);
|
|
767 #endif
|
|
768 Rmask = 0;
|
|
769 for ( i=0; i<vinfo.red.length; ++i ) {
|
|
770 Rmask <<= 1;
|
|
771 Rmask |= (0x00000001<<vinfo.red.offset);
|
|
772 }
|
|
773 Gmask = 0;
|
|
774 for ( i=0; i<vinfo.green.length; ++i ) {
|
|
775 Gmask <<= 1;
|
|
776 Gmask |= (0x00000001<<vinfo.green.offset);
|
|
777 }
|
|
778 Bmask = 0;
|
|
779 for ( i=0; i<vinfo.blue.length; ++i ) {
|
|
780 Bmask <<= 1;
|
|
781 Bmask |= (0x00000001<<vinfo.blue.offset);
|
|
782 }
|
|
783 if ( ! SDL_ReallocFormat(current, vinfo.bits_per_pixel,
|
|
784 Rmask, Gmask, Bmask, 0) ) {
|
|
785 return(NULL);
|
|
786 }
|
|
787
|
|
788 /* Get the fixed information about the console hardware.
|
|
789 This is necessary since finfo.line_length changes.
|
|
790 */
|
|
791 if ( ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
|
|
792 SDL_SetError("Couldn't get console hardware info");
|
|
793 return(NULL);
|
|
794 }
|
|
795
|
|
796 /* Save hardware palette, if needed */
|
|
797 FB_SavePalette(this, &finfo, &vinfo);
|
|
798
|
|
799 /* Set up the new mode framebuffer */
|
|
800 current->flags = (SDL_FULLSCREEN|SDL_HWSURFACE);
|
|
801 current->w = vinfo.xres;
|
|
802 current->h = vinfo.yres;
|
|
803 current->pitch = finfo.line_length;
|
|
804 current->pixels = mapped_mem+mapped_offset;
|
|
805
|
|
806 /* Let the application know we have a hardware palette */
|
|
807 switch (finfo.visual) {
|
|
808 case FB_VISUAL_PSEUDOCOLOR:
|
|
809 current->flags |= SDL_HWPALETTE;
|
|
810 break;
|
|
811 default:
|
|
812 break;
|
|
813 }
|
|
814
|
|
815 /* Update for double-buffering, if we can */
|
|
816 if ( flags & SDL_DOUBLEBUF ) {
|
|
817 if ( vinfo.yres_virtual == (height*2) ) {
|
|
818 current->flags |= SDL_DOUBLEBUF;
|
|
819 flip_page = 0;
|
|
820 flip_address[0] = (char *)current->pixels;
|
|
821 flip_address[1] = (char *)current->pixels+
|
|
822 current->h*current->pitch;
|
|
823 FB_FlipHWSurface(this, current);
|
|
824 }
|
|
825 }
|
|
826
|
|
827 /* Set up the information for hardware surfaces */
|
|
828 surfaces_mem = (char *)current->pixels +
|
|
829 vinfo.yres_virtual*current->pitch;
|
|
830 surfaces_len = (mapped_memlen-(surfaces_mem-mapped_mem));
|
|
831 FB_FreeHWSurfaces(this);
|
|
832 FB_InitHWSurfaces(this, surfaces_mem, surfaces_len);
|
|
833
|
|
834 /* Set the update rectangle function */
|
|
835 this->UpdateRects = FB_DirectUpdate;
|
|
836
|
|
837 /* We're done */
|
|
838 return(current);
|
|
839 }
|
|
840
|
|
841 #ifdef FBCON_DEBUG
|
|
842 void FB_DumpHWSurfaces(_THIS)
|
|
843 {
|
|
844 vidmem_bucket *bucket;
|
|
845
|
|
846 printf("Memory left: %d (%d total)\n", surfaces_memleft, surfaces_memtotal);
|
|
847 printf("\n");
|
|
848 printf(" Base Size\n");
|
|
849 for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
|
|
850 printf("Bucket: %p, %d (%s)\n", bucket->base, bucket->size, bucket->used ? "used" : "free");
|
|
851 if ( bucket->prev ) {
|
|
852 if ( bucket->base != bucket->prev->base+bucket->prev->size ) {
|
|
853 printf("Warning, corrupt bucket list! (prev)\n");
|
|
854 }
|
|
855 } else {
|
|
856 if ( bucket != &surfaces ) {
|
|
857 printf("Warning, corrupt bucket list! (!prev)\n");
|
|
858 }
|
|
859 }
|
|
860 if ( bucket->next ) {
|
|
861 if ( bucket->next->base != bucket->base+bucket->size ) {
|
|
862 printf("Warning, corrupt bucket list! (next)\n");
|
|
863 }
|
|
864 }
|
|
865 }
|
|
866 printf("\n");
|
|
867 }
|
|
868 #endif
|
|
869
|
|
870 static int FB_InitHWSurfaces(_THIS, char *base, int size)
|
|
871 {
|
|
872 surfaces.prev = NULL;
|
|
873 surfaces.used = 0;
|
|
874 surfaces.base = base;
|
|
875 surfaces.size = size;
|
|
876 surfaces.next = NULL;
|
|
877 surfaces_memtotal = size;
|
|
878 surfaces_memleft = size;
|
|
879 return(0);
|
|
880 }
|
|
881 static void FB_FreeHWSurfaces(_THIS)
|
|
882 {
|
|
883 vidmem_bucket *bucket, *freeable;
|
|
884
|
|
885 bucket = surfaces.next;
|
|
886 while ( bucket ) {
|
|
887 freeable = bucket;
|
|
888 bucket = bucket->next;
|
|
889 free(freeable);
|
|
890 }
|
|
891 surfaces.next = NULL;
|
|
892 }
|
|
893
|
|
894 static int FB_AllocHWSurface(_THIS, SDL_Surface *surface)
|
|
895 {
|
|
896 vidmem_bucket *bucket;
|
|
897 int size;
|
|
898 int extra;
|
|
899
|
|
900 /* Temporarily, we only allow surfaces the same width as display.
|
|
901 Some blitters require the pitch between two hardware surfaces
|
|
902 to be the same. Others have interesting alignment restrictions.
|
|
903 Until someone who knows these details looks at the code...
|
|
904 */
|
|
905 if ( surface->pitch > SDL_VideoSurface->pitch ) {
|
|
906 SDL_SetError("Surface requested wider than screen");
|
|
907 return(-1);
|
|
908 }
|
|
909 surface->pitch = SDL_VideoSurface->pitch;
|
|
910 size = surface->h * surface->pitch;
|
|
911 #ifdef FBCON_DEBUG
|
|
912 fprintf(stderr, "Allocating bucket of %d bytes\n", size);
|
|
913 #endif
|
|
914
|
|
915 /* Quick check for available mem */
|
|
916 if ( size > surfaces_memleft ) {
|
|
917 SDL_SetError("Not enough video memory");
|
|
918 return(-1);
|
|
919 }
|
|
920
|
|
921 /* Search for an empty bucket big enough */
|
|
922 for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
|
|
923 if ( ! bucket->used && (size <= bucket->size) ) {
|
|
924 break;
|
|
925 }
|
|
926 }
|
|
927 if ( bucket == NULL ) {
|
|
928 SDL_SetError("Video memory too fragmented");
|
|
929 return(-1);
|
|
930 }
|
|
931
|
|
932 /* Create a new bucket for left-over memory */
|
|
933 extra = (bucket->size - size);
|
|
934 if ( extra ) {
|
|
935 vidmem_bucket *newbucket;
|
|
936
|
|
937 #ifdef FBCON_DEBUG
|
|
938 fprintf(stderr, "Adding new free bucket of %d bytes\n", extra);
|
|
939 #endif
|
|
940 newbucket = (vidmem_bucket *)malloc(sizeof(*newbucket));
|
|
941 if ( newbucket == NULL ) {
|
|
942 SDL_OutOfMemory();
|
|
943 return(-1);
|
|
944 }
|
|
945 newbucket->prev = bucket;
|
|
946 newbucket->used = 0;
|
|
947 newbucket->base = bucket->base+size;
|
|
948 newbucket->size = extra;
|
|
949 newbucket->next = bucket->next;
|
|
950 if ( bucket->next ) {
|
|
951 bucket->next->prev = newbucket;
|
|
952 }
|
|
953 bucket->next = newbucket;
|
|
954 }
|
|
955
|
|
956 /* Set the current bucket values and return it! */
|
|
957 bucket->used = 1;
|
|
958 bucket->size = size;
|
|
959 #ifdef FBCON_DEBUG
|
|
960 fprintf(stderr, "Allocated %d bytes at %p\n", bucket->size, bucket->base);
|
|
961 #endif
|
|
962 surfaces_memleft -= size;
|
|
963 surface->flags |= SDL_HWSURFACE;
|
|
964 surface->pixels = bucket->base;
|
|
965 return(0);
|
|
966 }
|
|
967 static void FB_FreeHWSurface(_THIS, SDL_Surface *surface)
|
|
968 {
|
|
969 vidmem_bucket *bucket, *freeable;
|
|
970
|
|
971 /* Look for the bucket in the current list */
|
|
972 for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
|
|
973 if ( bucket->base == (char *)surface->pixels ) {
|
|
974 break;
|
|
975 }
|
|
976 }
|
|
977 if ( (bucket == NULL) || ! bucket->used ) {
|
|
978 return;
|
|
979 }
|
|
980
|
|
981 /* Add the memory back to the total */
|
|
982 #ifdef FBCON_DEBUG
|
|
983 printf("Freeing bucket of %d bytes\n", bucket->size);
|
|
984 #endif
|
|
985 surfaces_memleft += bucket->size;
|
|
986
|
|
987 /* Can we merge the space with surrounding buckets? */
|
|
988 bucket->used = 0;
|
|
989 if ( bucket->next && ! bucket->next->used ) {
|
|
990 #ifdef FBCON_DEBUG
|
|
991 printf("Merging with next bucket, for %d total bytes\n", bucket->size+bucket->next->size);
|
|
992 #endif
|
|
993 freeable = bucket->next;
|
|
994 bucket->size += bucket->next->size;
|
|
995 bucket->next = bucket->next->next;
|
|
996 if ( bucket->next ) {
|
|
997 bucket->next->prev = bucket;
|
|
998 }
|
|
999 free(freeable);
|
|
1000 }
|
|
1001 if ( bucket->prev && ! bucket->prev->used ) {
|
|
1002 #ifdef FBCON_DEBUG
|
|
1003 printf("Merging with previous bucket, for %d total bytes\n", bucket->prev->size+bucket->size);
|
|
1004 #endif
|
|
1005 freeable = bucket;
|
|
1006 bucket->prev->size += bucket->size;
|
|
1007 bucket->prev->next = bucket->next;
|
|
1008 if ( bucket->next ) {
|
|
1009 bucket->next->prev = bucket->prev;
|
|
1010 }
|
|
1011 free(freeable);
|
|
1012 }
|
|
1013 surface->pixels = NULL;
|
|
1014 }
|
|
1015 static int FB_LockHWSurface(_THIS, SDL_Surface *surface)
|
|
1016 {
|
|
1017 if ( surface == SDL_VideoSurface ) {
|
|
1018 SDL_mutexP(hw_lock);
|
|
1019 }
|
|
1020 return(0);
|
|
1021 }
|
|
1022 static void FB_UnlockHWSurface(_THIS, SDL_Surface *surface)
|
|
1023 {
|
|
1024 if ( surface == SDL_VideoSurface ) {
|
|
1025 SDL_mutexV(hw_lock);
|
|
1026 }
|
|
1027 }
|
|
1028
|
|
1029 static void FB_WaitVBL(_THIS)
|
|
1030 {
|
|
1031 #ifdef FBIOWAITRETRACE /* Heheh, this didn't make it into the main kernel */
|
|
1032 ioctl(console_fd, FBIOWAITRETRACE, 0);
|
|
1033 #endif
|
|
1034 return;
|
|
1035 }
|
|
1036
|
|
1037 static int FB_FlipHWSurface(_THIS, SDL_Surface *surface)
|
|
1038 {
|
|
1039 /* Wait for vertical retrace and then flip display */
|
|
1040 cache_vinfo.yoffset = flip_page*surface->h;
|
|
1041 wait_vbl(this);
|
|
1042 if ( ioctl(console_fd, FBIOPAN_DISPLAY, &cache_vinfo) < 0 ) {
|
|
1043 SDL_SetError("ioctl(FBIOPAN_DISPLAY) failed");
|
|
1044 return(-1);
|
|
1045 }
|
|
1046 flip_page = !flip_page;
|
|
1047
|
|
1048 surface->pixels = flip_address[flip_page];
|
|
1049 return(0);
|
|
1050 }
|
|
1051
|
|
1052 static void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
|
|
1053 {
|
|
1054 /* The application is already updating the visible video memory */
|
|
1055 return;
|
|
1056 }
|
|
1057
|
|
1058 #ifdef VGA16_FBCON_SUPPORT
|
|
1059 /* Code adapted with thanks from the XFree86 VGA16 driver! :) */
|
|
1060 #define writeGr(index, value) \
|
|
1061 outb(index, 0x3CE); \
|
|
1062 outb(value, 0x3CF);
|
|
1063 #define writeSeq(index, value) \
|
|
1064 outb(index, 0x3C4); \
|
|
1065 outb(value, 0x3C5);
|
|
1066
|
|
1067 static void FB_VGA16Update(_THIS, int numrects, SDL_Rect *rects)
|
|
1068 {
|
|
1069 SDL_Surface *screen;
|
|
1070 int width, height, FBPitch, left, i, j, SRCPitch, phase;
|
|
1071 register Uint32 m;
|
|
1072 Uint8 s1, s2, s3, s4;
|
|
1073 Uint32 *src, *srcPtr;
|
|
1074 Uint8 *dst, *dstPtr;
|
|
1075
|
|
1076 screen = this->screen;
|
|
1077 FBPitch = screen->w >> 3;
|
|
1078 SRCPitch = screen->pitch >> 2;
|
|
1079
|
|
1080 writeGr(0x03, 0x00);
|
|
1081 writeGr(0x05, 0x00);
|
|
1082 writeGr(0x01, 0x00);
|
|
1083 writeGr(0x08, 0xFF);
|
|
1084
|
|
1085 while(numrects--) {
|
|
1086 left = rects->x & ~7;
|
|
1087 width = (rects->w + 7) >> 3;
|
|
1088 height = rects->h;
|
|
1089 src = (Uint32*)screen->pixels + (rects->y * SRCPitch) + (left >> 2);
|
|
1090 dst = (Uint8*)mapped_mem + (rects->y * FBPitch) + (left >> 3);
|
|
1091
|
|
1092 if((phase = (long)dst & 3L)) {
|
|
1093 phase = 4 - phase;
|
|
1094 if(phase > width) phase = width;
|
|
1095 width -= phase;
|
|
1096 }
|
|
1097
|
|
1098 while(height--) {
|
|
1099 writeSeq(0x02, 1 << 0);
|
|
1100 dstPtr = dst;
|
|
1101 srcPtr = src;
|
|
1102 i = width;
|
|
1103 j = phase;
|
|
1104 while(j--) {
|
|
1105 m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4);
|
|
1106 *dstPtr++ = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
|
|
1107 srcPtr += 2;
|
|
1108 }
|
|
1109 while(i >= 4) {
|
|
1110 m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4);
|
|
1111 s1 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
|
|
1112 m = (srcPtr[3] & 0x01010101) | ((srcPtr[2] & 0x01010101) << 4);
|
|
1113 s2 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
|
|
1114 m = (srcPtr[5] & 0x01010101) | ((srcPtr[4] & 0x01010101) << 4);
|
|
1115 s3 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
|
|
1116 m = (srcPtr[7] & 0x01010101) | ((srcPtr[6] & 0x01010101) << 4);
|
|
1117 s4 = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
|
|
1118 *((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
|
|
1119 srcPtr += 8;
|
|
1120 dstPtr += 4;
|
|
1121 i -= 4;
|
|
1122 }
|
|
1123 while(i--) {
|
|
1124 m = (srcPtr[1] & 0x01010101) | ((srcPtr[0] & 0x01010101) << 4);
|
|
1125 *dstPtr++ = (m >> 24) | (m >> 15) | (m >> 6) | (m << 3);
|
|
1126 srcPtr += 2;
|
|
1127 }
|
|
1128
|
|
1129 writeSeq(0x02, 1 << 1);
|
|
1130 dstPtr = dst;
|
|
1131 srcPtr = src;
|
|
1132 i = width;
|
|
1133 j = phase;
|
|
1134 while(j--) {
|
|
1135 m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4);
|
|
1136 *dstPtr++ = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
|
|
1137 srcPtr += 2;
|
|
1138 }
|
|
1139 while(i >= 4) {
|
|
1140 m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4);
|
|
1141 s1 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
|
|
1142 m = (srcPtr[3] & 0x02020202) | ((srcPtr[2] & 0x02020202) << 4);
|
|
1143 s2 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
|
|
1144 m = (srcPtr[5] & 0x02020202) | ((srcPtr[4] & 0x02020202) << 4);
|
|
1145 s3 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
|
|
1146 m = (srcPtr[7] & 0x02020202) | ((srcPtr[6] & 0x02020202) << 4);
|
|
1147 s4 = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
|
|
1148 *((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
|
|
1149 srcPtr += 8;
|
|
1150 dstPtr += 4;
|
|
1151 i -= 4;
|
|
1152 }
|
|
1153 while(i--) {
|
|
1154 m = (srcPtr[1] & 0x02020202) | ((srcPtr[0] & 0x02020202) << 4);
|
|
1155 *dstPtr++ = (m >> 25) | (m >> 16) | (m >> 7) | (m << 2);
|
|
1156 srcPtr += 2;
|
|
1157 }
|
|
1158
|
|
1159 writeSeq(0x02, 1 << 2);
|
|
1160 dstPtr = dst;
|
|
1161 srcPtr = src;
|
|
1162 i = width;
|
|
1163 j = phase;
|
|
1164 while(j--) {
|
|
1165 m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4);
|
|
1166 *dstPtr++ = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
|
|
1167 srcPtr += 2;
|
|
1168 }
|
|
1169 while(i >= 4) {
|
|
1170 m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4);
|
|
1171 s1 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
|
|
1172 m = (srcPtr[3] & 0x04040404) | ((srcPtr[2] & 0x04040404) << 4);
|
|
1173 s2 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
|
|
1174 m = (srcPtr[5] & 0x04040404) | ((srcPtr[4] & 0x04040404) << 4);
|
|
1175 s3 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
|
|
1176 m = (srcPtr[7] & 0x04040404) | ((srcPtr[6] & 0x04040404) << 4);
|
|
1177 s4 = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
|
|
1178 *((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
|
|
1179 srcPtr += 8;
|
|
1180 dstPtr += 4;
|
|
1181 i -= 4;
|
|
1182 }
|
|
1183 while(i--) {
|
|
1184 m = (srcPtr[1] & 0x04040404) | ((srcPtr[0] & 0x04040404) << 4);
|
|
1185 *dstPtr++ = (m >> 26) | (m >> 17) | (m >> 8) | (m << 1);
|
|
1186 srcPtr += 2;
|
|
1187 }
|
|
1188
|
|
1189 writeSeq(0x02, 1 << 3);
|
|
1190 dstPtr = dst;
|
|
1191 srcPtr = src;
|
|
1192 i = width;
|
|
1193 j = phase;
|
|
1194 while(j--) {
|
|
1195 m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4);
|
|
1196 *dstPtr++ = (m >> 27) | (m >> 18) | (m >> 9) | m;
|
|
1197 srcPtr += 2;
|
|
1198 }
|
|
1199 while(i >= 4) {
|
|
1200 m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4);
|
|
1201 s1 = (m >> 27) | (m >> 18) | (m >> 9) | m;
|
|
1202 m = (srcPtr[3] & 0x08080808) | ((srcPtr[2] & 0x08080808) << 4);
|
|
1203 s2 = (m >> 27) | (m >> 18) | (m >> 9) | m;
|
|
1204 m = (srcPtr[5] & 0x08080808) | ((srcPtr[4] & 0x08080808) << 4);
|
|
1205 s3 = (m >> 27) | (m >> 18) | (m >> 9) | m;
|
|
1206 m = (srcPtr[7] & 0x08080808) | ((srcPtr[6] & 0x08080808) << 4);
|
|
1207 s4 = (m >> 27) | (m >> 18) | (m >> 9) | m;
|
|
1208 *((Uint32*)dstPtr) = s1 | (s2 << 8) | (s3 << 16) | (s4 << 24);
|
|
1209 srcPtr += 8;
|
|
1210 dstPtr += 4;
|
|
1211 i -= 4;
|
|
1212 }
|
|
1213 while(i--) {
|
|
1214 m = (srcPtr[1] & 0x08080808) | ((srcPtr[0] & 0x08080808) << 4);
|
|
1215 *dstPtr++ = (m >> 27) | (m >> 18) | (m >> 9) | m;
|
|
1216 srcPtr += 2;
|
|
1217 }
|
|
1218
|
|
1219 dst += FBPitch;
|
|
1220 src += SRCPitch;
|
|
1221 }
|
|
1222 rects++;
|
|
1223 }
|
|
1224 }
|
|
1225 #endif /* VGA16_FBCON_SUPPORT */
|
|
1226
|
|
1227 void FB_SavePaletteTo(_THIS, int palette_len, __u16 *area)
|
|
1228 {
|
|
1229 struct fb_cmap cmap;
|
|
1230
|
|
1231 cmap.start = 0;
|
|
1232 cmap.len = palette_len;
|
|
1233 cmap.red = &area[0*palette_len];
|
|
1234 cmap.green = &area[1*palette_len];
|
|
1235 cmap.blue = &area[2*palette_len];
|
|
1236 cmap.transp = NULL;
|
|
1237 ioctl(console_fd, FBIOGETCMAP, &cmap);
|
|
1238 }
|
|
1239
|
|
1240 void FB_RestorePaletteFrom(_THIS, int palette_len, __u16 *area)
|
|
1241 {
|
|
1242 struct fb_cmap cmap;
|
|
1243
|
|
1244 cmap.start = 0;
|
|
1245 cmap.len = palette_len;
|
|
1246 cmap.red = &area[0*palette_len];
|
|
1247 cmap.green = &area[1*palette_len];
|
|
1248 cmap.blue = &area[2*palette_len];
|
|
1249 cmap.transp = NULL;
|
|
1250 ioctl(console_fd, FBIOPUTCMAP, &cmap);
|
|
1251 }
|
|
1252
|
|
1253 static void FB_SavePalette(_THIS, struct fb_fix_screeninfo *finfo,
|
|
1254 struct fb_var_screeninfo *vinfo)
|
|
1255 {
|
|
1256 int i;
|
|
1257
|
|
1258 /* Save hardware palette, if needed */
|
|
1259 if ( finfo->visual == FB_VISUAL_PSEUDOCOLOR ) {
|
|
1260 saved_cmaplen = 1<<vinfo->bits_per_pixel;
|
|
1261 saved_cmap=(__u16 *)malloc(3*saved_cmaplen*sizeof(*saved_cmap));
|
|
1262 if ( saved_cmap != NULL ) {
|
|
1263 FB_SavePaletteTo(this, saved_cmaplen, saved_cmap);
|
|
1264 }
|
|
1265 }
|
|
1266
|
|
1267 /* Added support for FB_VISUAL_DIRECTCOLOR.
|
|
1268 With this mode pixel information is passed through the palette...
|
|
1269 Neat fading and gamma correction effects can be had by simply
|
|
1270 fooling around with the palette instead of changing the pixel
|
|
1271 values themselves... Very neat!
|
|
1272
|
|
1273 Adam Meyerowitz 1/19/2000
|
|
1274 ameyerow@optonline.com
|
|
1275 */
|
|
1276 if ( finfo->visual == FB_VISUAL_DIRECTCOLOR ) {
|
|
1277 __u16 new_entries[3*256];
|
|
1278
|
|
1279 /* Save the colormap */
|
|
1280 saved_cmaplen = 256;
|
|
1281 saved_cmap=(__u16 *)malloc(3*saved_cmaplen*sizeof(*saved_cmap));
|
|
1282 if ( saved_cmap != NULL ) {
|
|
1283 FB_SavePaletteTo(this, saved_cmaplen, saved_cmap);
|
|
1284 }
|
|
1285
|
|
1286 /* Allocate new identity colormap */
|
|
1287 for ( i=0; i<256; ++i ) {
|
|
1288 new_entries[(0*256)+i] =
|
|
1289 new_entries[(1*256)+i] =
|
|
1290 new_entries[(2*256)+i] = (i<<8)|i;
|
|
1291 }
|
|
1292 FB_RestorePaletteFrom(this, 256, new_entries);
|
|
1293 }
|
|
1294 }
|
|
1295
|
|
1296 static void FB_RestorePalette(_THIS)
|
|
1297 {
|
|
1298 /* Restore the original palette */
|
|
1299 if ( saved_cmap ) {
|
|
1300 FB_RestorePaletteFrom(this, saved_cmaplen, saved_cmap);
|
|
1301 free(saved_cmap);
|
|
1302 saved_cmap = NULL;
|
|
1303 }
|
|
1304 }
|
|
1305
|
|
1306 static int FB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
|
|
1307 {
|
|
1308 int i;
|
|
1309 __u16 r[256];
|
|
1310 __u16 g[256];
|
|
1311 __u16 b[256];
|
|
1312 struct fb_cmap cmap;
|
|
1313
|
|
1314 /* Set up the colormap */
|
|
1315 for (i = 0; i < ncolors; i++) {
|
|
1316 r[i] = colors[i].r << 8;
|
|
1317 g[i] = colors[i].g << 8;
|
|
1318 b[i] = colors[i].b << 8;
|
|
1319 }
|
|
1320 cmap.start = firstcolor;
|
|
1321 cmap.len = ncolors;
|
|
1322 cmap.red = r;
|
|
1323 cmap.green = g;
|
|
1324 cmap.blue = b;
|
|
1325 cmap.transp = NULL;
|
|
1326
|
|
1327 if( (ioctl(console_fd, FBIOPUTCMAP, &cmap) < 0) ||
|
|
1328 !(this->screen->flags & SDL_HWPALETTE) ) {
|
|
1329 colors = this->screen->format->palette->colors;
|
|
1330 ncolors = this->screen->format->palette->ncolors;
|
|
1331 cmap.start = 0;
|
|
1332 cmap.len = ncolors;
|
|
1333 memset(r, 0, sizeof(r));
|
|
1334 memset(g, 0, sizeof(g));
|
|
1335 memset(b, 0, sizeof(b));
|
|
1336 if ( ioctl(console_fd, FBIOGETCMAP, &cmap) == 0 ) {
|
|
1337 for ( i=ncolors-1; i>=0; --i ) {
|
|
1338 colors[i].r = (r[i]>>8);
|
|
1339 colors[i].g = (g[i]>>8);
|
|
1340 colors[i].b = (b[i]>>8);
|
|
1341 }
|
|
1342 }
|
|
1343 return(0);
|
|
1344 }
|
|
1345 return(1);
|
|
1346 }
|
|
1347
|
|
1348 /* Note: If we are terminated, this could be called in the middle of
|
|
1349 another SDL video routine -- notably UpdateRects.
|
|
1350 */
|
|
1351 static void FB_VideoQuit(_THIS)
|
|
1352 {
|
|
1353 int i, j;
|
|
1354
|
|
1355 if ( this->screen ) {
|
|
1356 /* Clear screen and tell SDL not to free the pixels */
|
|
1357 if ( this->screen->pixels && FB_InGraphicsMode(this) ) {
|
|
1358 #ifdef __powerpc__ /* SIGBUS when using memset() ?? */
|
|
1359 Uint8 *rowp = (Uint8 *)this->screen->pixels;
|
|
1360 int left = this->screen->pitch*this->screen->h;
|
|
1361 while ( left-- ) { *rowp++ = 0; }
|
|
1362 #else
|
|
1363 memset(this->screen->pixels,0,this->screen->h*this->screen->pitch);
|
|
1364 #endif
|
|
1365 }
|
|
1366 /* This test fails when using the VGA16 shadow memory */
|
|
1367 if ( ((char *)this->screen->pixels >= mapped_mem) &&
|
|
1368 ((char *)this->screen->pixels < (mapped_mem+mapped_memlen)) ) {
|
|
1369 this->screen->pixels = NULL;
|
|
1370 }
|
|
1371 }
|
|
1372
|
|
1373 /* Clear the lock mutex */
|
|
1374 if ( hw_lock ) {
|
|
1375 SDL_DestroyMutex(hw_lock);
|
|
1376 hw_lock = NULL;
|
|
1377 }
|
|
1378
|
|
1379 /* Clean up defined video modes */
|
|
1380 for ( i=0; i<NUM_MODELISTS; ++i ) {
|
|
1381 if ( SDL_modelist[i] != NULL ) {
|
|
1382 for ( j=0; SDL_modelist[i][j]; ++j ) {
|
|
1383 free(SDL_modelist[i][j]);
|
|
1384 }
|
|
1385 free(SDL_modelist[i]);
|
|
1386 SDL_modelist[i] = NULL;
|
|
1387 }
|
|
1388 }
|
|
1389
|
|
1390 /* Clean up the memory bucket list */
|
|
1391 FB_FreeHWSurfaces(this);
|
|
1392
|
|
1393 /* Close console and input file descriptors */
|
|
1394 if ( console_fd > 0 ) {
|
|
1395 /* Unmap the video framebuffer and I/O registers */
|
|
1396 if ( mapped_mem ) {
|
|
1397 munmap(mapped_mem, mapped_memlen);
|
|
1398 mapped_mem = NULL;
|
|
1399 }
|
|
1400 if ( mapped_io ) {
|
|
1401 munmap(mapped_io, mapped_iolen);
|
|
1402 mapped_io = NULL;
|
|
1403 }
|
|
1404
|
|
1405 /* Restore the original video mode and palette */
|
|
1406 if ( FB_InGraphicsMode(this) ) {
|
|
1407 FB_RestorePalette(this);
|
|
1408 ioctl(console_fd, FBIOPUT_VSCREENINFO, &saved_vinfo);
|
|
1409 }
|
|
1410
|
|
1411 /* We're all done with the framebuffer */
|
|
1412 close(console_fd);
|
|
1413 console_fd = -1;
|
|
1414 }
|
|
1415 FB_CloseMouse(this);
|
|
1416 FB_CloseKeyboard(this);
|
|
1417 }
|