comparison src/video/fbcon/SDL_fbvideo.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children 332f458469f0
comparison
equal deleted inserted replaced
-1:000000000000 0:74212992fb08
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 }